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 **/ 019package lucee.runtime.functions.closure; 020 021import java.util.ArrayList; 022import java.util.Enumeration; 023import java.util.Iterator; 024import java.util.List; 025import java.util.ListIterator; 026import java.util.Map.Entry; 027import java.util.concurrent.ExecutorService; 028import java.util.concurrent.Executors; 029import java.util.concurrent.Future; 030 031import lucee.runtime.PageContext; 032import lucee.runtime.concurrency.Data; 033import lucee.runtime.concurrency.UDFCaller2; 034import lucee.runtime.exp.CasterException; 035import lucee.runtime.exp.FunctionException; 036import lucee.runtime.exp.PageException; 037import lucee.runtime.functions.BIF; 038import lucee.runtime.op.Caster; 039import lucee.runtime.type.Array; 040import lucee.runtime.type.Collection.Key; 041import lucee.runtime.type.Iteratorable; 042import lucee.runtime.type.Query; 043import lucee.runtime.type.Struct; 044import lucee.runtime.type.UDF; 045import lucee.runtime.type.it.ForEachQueryIterator; 046import lucee.runtime.type.scope.ArgumentIntKey; 047import lucee.runtime.type.util.ListUtil; 048import lucee.runtime.type.util.StringListData; 049 050public class Every extends BIF { 051 052 private static final long serialVersionUID = -5940580562772523622L; 053 054 public static boolean call(PageContext pc , Object obj, UDF udf) throws PageException { 055 return _call(pc, obj, udf, false,20); 056 } 057 public static boolean call(PageContext pc , Object obj, UDF udf, boolean parallel) throws PageException { 058 return _call(pc, obj, udf, parallel, 20); 059 } 060 public static boolean call(PageContext pc , Object obj, UDF udf, boolean parallel, double maxThreads) throws PageException { 061 return _call(pc, obj, udf, parallel, (int)maxThreads); 062 } 063 064 public static boolean _call(PageContext pc , Object obj, UDF udf, boolean parallel, int maxThreads) throws PageException { 065 066 ExecutorService execute=null; 067 List<Future<Data<Object>>> futures=null; 068 if(parallel) { 069 execute = Executors.newFixedThreadPool(maxThreads); 070 futures=new ArrayList<Future<Data<Object>>>(); 071 } 072 073 boolean res; 074 075 // Array 076 if(obj instanceof Array) { 077 res=invoke(pc, (Array)obj, udf,execute,futures); 078 } 079 080 // Query 081 else if(obj instanceof Query) { 082 res=invoke(pc, (Query)obj, udf,execute,futures); 083 } 084 // Struct 085 else if(obj instanceof Struct) { 086 res=invoke(pc, (Struct)obj, udf,execute,futures); 087 } 088 // other Iteratorable 089 else if(obj instanceof Iteratorable) { 090 res=invoke(pc, (Iteratorable)obj, udf,execute,futures); 091 } 092 // Map 093 else if(obj instanceof java.util.Map) { 094 res=invoke(pc, (java.util.Map)obj, udf,execute,futures); 095 } 096 //List 097 else if(obj instanceof List) { 098 res=invoke(pc, (List)obj, udf,execute,futures); 099 } 100 // Iterator 101 else if(obj instanceof Iterator) { 102 res=invoke(pc, (Iterator)obj, udf,execute,futures); 103 } 104 // Enumeration 105 else if(obj instanceof Enumeration) { 106 res=invoke(pc, (Enumeration)obj, udf,execute,futures); 107 } 108 // String List 109 else if(obj instanceof StringListData) { 110 res=invoke(pc, (StringListData)obj, udf,execute,futures); 111 } 112 else 113 throw new FunctionException(pc, "Every", 1, "data", "cannot iterate througth this type "+Caster.toTypeName(obj.getClass())); 114 115 if(parallel) res=afterCall(pc,futures,execute); 116 117 return res; 118 } 119 120 private static boolean invoke(PageContext pc, Array arr, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 121 Iterator<Entry<Key, Object>> it = arr.entryIterator(); 122 Entry<Key, Object> e; 123 boolean async=es!=null; 124 Object res; 125 while(it.hasNext()){ 126 e = it.next(); 127 res=_inv(pc, udf, new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),arr},e.getKey(),e.getValue(), es, futures); 128 if(!async && !Caster.toBooleanValue(res)) { 129 return false; 130 } 131 } 132 return true; 133 } 134 135 private static boolean invoke(PageContext pc, Query qry, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 136 final int pid=pc.getId(); 137 ForEachQueryIterator it=new ForEachQueryIterator(qry, pid); 138 boolean async=es!=null; 139 double r; 140 Object res,row; 141 try{ 142 while(it.hasNext()){ 143 row=it.next(); 144 r = Caster.toDoubleValue(qry.getCurrentrow(pid)); 145 res=_inv(pc, udf, new Object[]{row,r,qry},r,row, es, futures); 146 if(!async && !Caster.toBooleanValue(res)) { 147 return false; 148 } 149 } 150 } 151 finally { 152 it.reset(); 153 } 154 return true; 155 } 156 157 158 private static boolean invoke(PageContext pc, StringListData sld, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 159 Array arr = ListUtil.listToArray(sld.list, sld.delimiter,sld.includeEmptyFieldsx,sld.multiCharacterDelimiter); 160 161 Iterator<Entry<Key, Object>> it = arr.entryIterator(); 162 Entry<Key, Object> e; 163 boolean async=es!=null; 164 Object res; 165 while(it.hasNext()){ 166 e = it.next(); 167 res=_inv(pc, udf, new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),sld.list,sld.delimiter},e.getKey(),e.getValue(), es, futures); 168 if(!async && !Caster.toBooleanValue(res)) { 169 return false; 170 } 171 } 172 return true; 173 } 174 175 176 private static boolean invoke(PageContext pc, List list, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 177 ListIterator it = list.listIterator(); 178 boolean async=es!=null; 179 Object res,v; 180 int index; 181 ArgumentIntKey k; 182 while(it.hasNext()){ 183 index = it.nextIndex(); 184 k = ArgumentIntKey.init(index); 185 v = it.next(); 186 res=_inv(pc, udf, new Object[]{v,Caster.toDoubleValue(k.getString()),list},k,v, es, futures); 187 if(!async && !Caster.toBooleanValue(res)) return false; 188 } 189 return true; 190 } 191 192 private static boolean invoke(PageContext pc, Struct sct, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws PageException { 193 Iterator<Entry<Key, Object>> it = sct.entryIterator(); 194 Entry<Key, Object> e; 195 boolean async=es!=null; 196 Object res; 197 while(it.hasNext()){ 198 e = it.next(); 199 res=_inv(pc, udf, new Object[]{e.getKey().getString(),e.getValue(),sct},e.getKey(),e.getValue(), es, futures); 200 if(!async && !Caster.toBooleanValue(res)) return false; 201 } 202 return true; 203 } 204 205 private static boolean invoke(PageContext pc, java.util.Map map, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws PageException { 206 Iterator<Entry> it = map.entrySet().iterator(); 207 Entry e; 208 boolean async=es!=null; 209 Object res; 210 while(it.hasNext()){ 211 e = it.next(); 212 res=_inv(pc, udf, new Object[]{e.getKey(),e.getValue(),map},e.getKey(),e.getValue(), es, futures); 213 if(!async && !Caster.toBooleanValue(res)) return false; 214 } 215 return true; 216 } 217 218 private static boolean invoke(PageContext pc, Iteratorable i, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws PageException { 219 Iterator<Entry<Key, Object>> it = i.entryIterator(); 220 221 Entry<Key, Object> e; 222 boolean async=es!=null; 223 Object res; 224 while(it.hasNext()){ 225 e = it.next(); 226 res=_inv(pc, udf, new Object[]{e.getKey().getString(),e.getValue()},e.getKey(),e.getValue(), es, futures); 227 if(!async && !Caster.toBooleanValue(res)) return false; 228 } 229 return true; 230 } 231 232 private static boolean invoke(PageContext pc, Iterator it, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws PageException { 233 234 Object v; 235 boolean async=es!=null; 236 Object res; 237 int count=0; 238 ArgumentIntKey k; 239 while(it.hasNext()){ 240 v = it.next(); 241 k = ArgumentIntKey.init(++count); 242 res=_inv(pc, udf, new Object[]{v},k,v, es, futures); 243 if(!async && !Caster.toBooleanValue(res)) return false; 244 } 245 return true; 246 } 247 248 private static boolean invoke(PageContext pc, Enumeration e, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws PageException { 249 250 Object v; 251 boolean async=es!=null; 252 Object res; 253 int count=0; 254 ArgumentIntKey k; 255 while(e.hasMoreElements()){ 256 v = e.nextElement(); 257 k = ArgumentIntKey.init(++count); 258 res=_inv(pc, udf, new Object[]{v},k,v, es, futures); 259 if(!async && !Caster.toBooleanValue(res)) return false; 260 } 261 return true; 262 } 263 264 private static Object _inv(PageContext pc, UDF udf, Object[] args,Object key,Object value,ExecutorService es,List<Future<Data<Object>>> futures) throws PageException { 265 if(es==null) { 266 return udf.call(pc, args, true); 267 } 268 futures.add(es.submit(new UDFCaller2<Object>(pc, udf, args, null,true))); 269 return null; 270 } 271 272 public static boolean afterCall(PageContext pc, List<Future<Data<Object>>> futures, ExecutorService es) throws PageException { 273 try{ 274 Iterator<Future<Data<Object>>> it = futures.iterator(); 275 Data<Object> d; 276 while(it.hasNext()){ 277 d = it.next().get(); 278 if(!Caster.toBooleanValue(d.result)) return false; 279 pc.write(d.output); 280 } 281 return true; 282 } 283 catch(Exception e){ 284 throw Caster.toPageException(e); 285 } 286 finally { 287 es.shutdown(); 288 } 289 } 290 291 @Override 292 public Object invoke(PageContext pc, Object[] args) throws PageException { 293 294 if(args.length==2) 295 return call(pc, (args[0]), Caster.toFunction(args[1])); 296 if(args.length==3) 297 return call(pc, (args[0]), Caster.toFunction(args[1]), Caster.toBooleanValue(args[2])); 298 if(args.length==4) 299 return call(pc, (args[0]), Caster.toFunction(args[1]), Caster.toBooleanValue(args[2]), Caster.toDoubleValue(args[3])); 300 301 throw new FunctionException(pc, "Every", 2, 4, args.length); 302 303 304 } 305 306}