001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019/** 020 * Implements the CFML Function arraysort 021 */ 022package lucee.runtime.functions.arrays; 023 024import java.util.Arrays; 025import java.util.Collections; 026import java.util.Comparator; 027import java.util.List; 028 029import lucee.runtime.PageContext; 030import lucee.runtime.exp.CasterException; 031import lucee.runtime.exp.FunctionException; 032import lucee.runtime.exp.PageException; 033import lucee.runtime.exp.PageRuntimeException; 034import lucee.runtime.functions.BIF; 035import lucee.runtime.op.Caster; 036import lucee.runtime.type.Array; 037import lucee.runtime.type.Closure; 038import lucee.runtime.type.UDF; 039import lucee.runtime.type.util.ArrayUtil; 040 041public final class ArraySort extends BIF { 042 043 private static final long serialVersionUID = -747941236369495141L; 044 045 public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure) throws PageException { 046 return call(pc , objArr, sortTypeOrClosure, "asc",false); 047 } 048 public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure, String sortorder) throws PageException { 049 return call(pc , objArr, sortTypeOrClosure, sortorder,false); 050 } 051 052 053 public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure, String sortorder, boolean localeSensitive) throws PageException { 054 055 // Comparator 056 Comparator comp; 057 if(sortTypeOrClosure instanceof UDF) 058 comp=new UDFComparator(pc, (UDF)sortTypeOrClosure); 059 else 060 comp=ArrayUtil.toComparator(pc,Caster.toString(sortTypeOrClosure), sortorder,localeSensitive); 061 062 // we always need to convert the original object, because we do not return the result 063 if(objArr instanceof Array) ((Array)objArr).sort(comp); 064 else if(objArr instanceof List) Collections.sort((List)objArr, comp); 065 else if(objArr instanceof Object[]) Arrays.sort((Object[])objArr, comp); 066 // else if(objArr instanceof boolean[]) Arrays.sort((boolean[])objArr); 067 else if(objArr instanceof byte[]) Arrays.sort((byte[])objArr); 068 else if(objArr instanceof char[]) Arrays.sort((char[])objArr); 069 else if(objArr instanceof short[]) Arrays.sort((short[])objArr); 070 else if(objArr instanceof int[]) Arrays.sort((int[])objArr); 071 else if(objArr instanceof long[]) Arrays.sort((long[])objArr); 072 else if(objArr instanceof float[]) Arrays.sort((float[])objArr); 073 else if(objArr instanceof double[]) Arrays.sort((double[])objArr); 074 else throw new FunctionException(pc, "ArraySort", 1, "array", "cannot sort object from type ["+Caster.toTypeName(objArr)+"]"); 075 076 return true; 077 } 078 079 080 081 // used for member function 082 public static boolean call(PageContext pc , Array array, Object sortTypeOrClosure) throws PageException { 083 return call(pc , array, sortTypeOrClosure, "asc",false); 084 } 085 086 public static boolean call(PageContext pc , Array array, Object sortTypeOrClosure, String sortorder) throws PageException { 087 return call(pc , array, sortTypeOrClosure, sortorder,false); 088 } 089 090 public static boolean call(PageContext pc , Array arr, Object sortTypeOrClosure, String sortorder, boolean localeSensitive) throws PageException { 091 // Comparator 092 Comparator comp; 093 if(sortTypeOrClosure instanceof UDF) 094 comp=new UDFComparator(pc, (UDF)sortTypeOrClosure); 095 else 096 comp=ArrayUtil.toComparator(pc,Caster.toString(sortTypeOrClosure), sortorder,localeSensitive); 097 098 arr.sort(comp); 099 return true; 100 } 101 102 @Override 103 public Object invoke(PageContext pc, Object[] args) throws PageException { 104 if(args.length==2)return call(pc,Caster.toArray(args[0]),args[1]); 105 if(args.length==3)return call(pc,Caster.toArray(args[0]),args[1],Caster.toString(args[2])); 106 return call(pc,Caster.toArray(args[0]),args[1],Caster.toString(args[2]),Caster.toBooleanValue(args[3])); 107 } 108} 109 110class UDFComparator implements Comparator<Object> { 111 112 private UDF udf; 113 private Object[] args=new Object[2]; 114 private PageContext pc; 115 116 public UDFComparator(PageContext pc,UDF udf){ 117 this.pc=pc; 118 this.udf=udf; 119 } 120 121 @Override 122 public int compare(Object oLeft, Object oRight) { 123 try { 124 args[0]=oLeft; 125 args[1]=oRight; 126 Object res = udf.call(pc, args, false); 127 Integer i = Caster.toInteger(res,null); 128 if(i==null) throw new FunctionException(pc,"ArraySort",2,"function","return value of the "+(udf instanceof Closure?"closure":"function ["+udf.getFunctionName()+"]")+" cannot be casted to a integer.",CasterException.createMessage(res, "integer")); 129 return i.intValue(); 130 } 131 catch (PageException pe) { 132 throw new PageRuntimeException(pe); 133 } 134 } 135 136}