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 arrayavg 021 */ 022package lucee.runtime.functions.closure; 023 024import java.util.ArrayList; 025import java.util.Enumeration; 026import java.util.Iterator; 027import java.util.List; 028import java.util.ListIterator; 029import java.util.Map; 030import java.util.Map.Entry; 031import java.util.concurrent.ExecutorService; 032import java.util.concurrent.Executors; 033import java.util.concurrent.Future; 034 035import lucee.runtime.PageContext; 036import lucee.runtime.concurrency.Data; 037import lucee.runtime.concurrency.UDFCaller2; 038import lucee.runtime.exp.FunctionException; 039import lucee.runtime.exp.PageException; 040import lucee.runtime.functions.BIF; 041import lucee.runtime.op.Caster; 042import lucee.runtime.type.Array; 043import lucee.runtime.type.Collection.Key; 044import lucee.runtime.type.Iteratorable; 045import lucee.runtime.type.Query; 046import lucee.runtime.type.UDF; 047import lucee.runtime.type.it.ForEachQueryIterator; 048import lucee.runtime.type.util.ListUtil; 049import lucee.runtime.type.util.StringListData; 050 051 052public final class Each extends BIF { 053 054 private static final long serialVersionUID = 1955185705863596525L; 055 056 public static String call(PageContext pc , Object obj, UDF udf) throws PageException { 057 return _call(pc, obj, udf, false,20); 058 } 059 public static String call(PageContext pc , Object obj, UDF udf, boolean parallel) throws PageException { 060 return _call(pc, obj, udf, parallel, 20); 061 } 062 public static String call(PageContext pc , Object obj, UDF udf, boolean parallel, double maxThreads) throws PageException { 063 return _call(pc, obj, udf, parallel, (int)maxThreads); 064 } 065 066 private static String _call(PageContext pc , Object obj, UDF udf, boolean parallel, int maxThreads) throws PageException { 067 ExecutorService execute=null; 068 List<Future<Data<Object>>> futures=null; 069 if(parallel) { 070 execute = Executors.newFixedThreadPool(maxThreads); 071 futures=new ArrayList<Future<Data<Object>>>(); 072 } 073 074 // Array 075 if(obj instanceof Array) { 076 invoke(pc, (Array)obj, udf,execute,futures); 077 } 078 079 // Query 080 else if(obj instanceof Query) { 081 invoke(pc, (Query)obj, udf,execute,futures); 082 } 083 084 085 // other Iteratorable 086 else if(obj instanceof Iteratorable) { 087 invoke(pc, (Iteratorable)obj, udf,execute,futures); 088 } 089 // Map 090 else if(obj instanceof Map) { 091 Iterator it = ((Map)obj).entrySet().iterator(); 092 Entry e; 093 while(it.hasNext()){ 094 e = (Entry) it.next(); 095 _call(pc,udf,new Object[]{e.getKey(),e.getValue(),obj},execute,futures); 096 //udf.call(pc, new Object[]{e.getKey(),e.getValue()}, true); 097 } 098 } 099 //List 100 else if(obj instanceof List) { 101 ListIterator it = ((List)obj).listIterator(); 102 int index; 103 while(it.hasNext()){ 104 index=it.nextIndex(); 105 _call(pc,udf,new Object[]{it.next(),new Double(index),obj},execute,futures); 106 //udf.call(pc, new Object[]{it.next()}, true); 107 } 108 } 109 110 // Iterator 111 else if(obj instanceof Iterator) { 112 Iterator it = (Iterator)obj; 113 while(it.hasNext()){ 114 _call(pc,udf, new Object[]{it.next()},execute,futures); 115 //udf.call(pc, new Object[]{it.next()}, true); 116 } 117 } 118 // Enumeration 119 else if(obj instanceof Enumeration) { 120 Enumeration e = (Enumeration)obj; 121 while(e.hasMoreElements()){ 122 _call(pc,udf,new Object[]{e.nextElement()},execute,futures); 123 //udf.call(pc, new Object[]{e.nextElement()}, true); 124 } 125 } 126 // StringListData 127 else if(obj instanceof StringListData) { 128 invoke(pc, (StringListData)obj, udf, execute, futures); 129 } 130 131 else 132 throw new FunctionException(pc, "Each", 1, "data", "cannot iterate througth this type "+Caster.toTypeName(obj.getClass())); 133 134 if(parallel) afterCall(pc,futures,execute); 135 136 137 return null; 138 } 139 140 public static void afterCall(PageContext pc, List<Future<Data<Object>>> futures, ExecutorService es) throws PageException { 141 try{ 142 Iterator<Future<Data<Object>>> it = futures.iterator(); 143 //Future<String> f; 144 while(it.hasNext()){ 145 pc.write(it.next().get().output); 146 } 147 } 148 catch(Exception e){ 149 throw Caster.toPageException(e); 150 } 151 finally { 152 es.shutdown(); 153 } 154 } 155 public static void invoke(PageContext pc , Array array, UDF udf,ExecutorService execute,List<Future<Data<Object>>> futures) throws PageException { 156 Iterator<Entry<Key, Object>> it = array.entryIterator(); 157 Entry<Key, Object> e; 158 while(it.hasNext()){ 159 e=it.next(); 160 _call(pc,udf,new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),array},execute,futures); 161 //udf.call(pc, new Object[]{it.next()}, true); 162 } 163 } 164 165 public static void invoke(PageContext pc ,Query qry, UDF udf,ExecutorService execute,List<Future<Data<Object>>> futures) throws PageException { 166 final int pid=pc.getId(); 167 ForEachQueryIterator it=new ForEachQueryIterator(qry, pid); 168 try{ 169 Object row; 170 //Entry<Key, Object> e; 171 while(it.hasNext()){ 172 row=it.next(); 173 _call(pc,udf,new Object[]{row,Caster.toDoubleValue(qry.getCurrentrow(pid)),qry},execute,futures); 174 } 175 } 176 finally { 177 it.reset(); 178 } 179 } 180 181 public static void invoke(PageContext pc , Iteratorable coll, UDF udf,ExecutorService execute,List<Future<Data<Object>>> futures) throws PageException { 182 Iterator<Entry<Key, Object>> it = coll.entryIterator(); 183 Entry<Key, Object> e; 184 while(it.hasNext()){ 185 e = it.next(); 186 _call(pc,udf,new Object[]{e.getKey().getString(),e.getValue(),coll},execute,futures); 187 //udf.call(pc, new Object[]{e.getKey().getString(),e.getValue()}, true); 188 } 189 } 190 191 private static void invoke(PageContext pc, StringListData sld, UDF udf, ExecutorService execute, List<Future<Data<Object>>> futures) throws PageException { 192 Array arr = ListUtil.listToArray(sld.list, sld.delimiter,sld.includeEmptyFieldsx,sld.multiCharacterDelimiter); 193 194 195 Iterator<Entry<Key, Object>> it = arr.entryIterator(); 196 Entry<Key, Object> e; 197 while(it.hasNext()){ 198 e=it.next(); 199 _call(pc,udf,new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),sld.list,sld.delimiter},execute,futures); 200 } 201 202 } 203 204 private static void _call(PageContext pc, UDF udf, Object[] args,ExecutorService es,List<Future<Data<Object>>> futures) throws PageException { 205 if(es==null) { 206 udf.call(pc, args, true); 207 return; 208 } 209 futures.add(es.submit(new UDFCaller2<Object>(pc, udf, args,null, true))); 210 } 211 212 @Override 213 public Object invoke(PageContext pc, Object[] args) throws PageException { 214 215 if(args.length==2) 216 return call(pc, args[0], Caster.toFunction(args[1])); 217 if(args.length==3) 218 return call(pc, args[0], Caster.toFunction(args[1]), Caster.toBooleanValue(args[2])); 219 if(args.length==4) 220 return call(pc, args[0], Caster.toFunction(args[1]), Caster.toBooleanValue(args[2]), Caster.toDoubleValue(args[3])); 221 222 throw new FunctionException(pc, "Each", 2, 4, args.length); 223 224 225 } 226 227}