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 Some 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 // Query 080 else if(obj instanceof Query) { 081 res=invoke(pc, (Query)obj, udf,execute,futures); 082 } 083 // Struct 084 else if(obj instanceof Struct) { 085 res=invoke(pc, (Struct)obj, udf,execute,futures); 086 } 087 // other Iteratorable 088 else if(obj instanceof Iteratorable) { 089 res=invoke(pc, (Iteratorable)obj, udf,execute,futures); 090 } 091 // Map 092 else if(obj instanceof java.util.Map) { 093 res=invoke(pc, (java.util.Map)obj, udf,execute,futures); 094 } 095 //List 096 else if(obj instanceof List) { 097 res=invoke(pc, (List)obj, udf,execute,futures); 098 } 099 // Iterator 100 else if(obj instanceof Iterator) { 101 res=invoke(pc, (Iterator)obj, udf,execute,futures); 102 } 103 // Enumeration 104 else if(obj instanceof Enumeration) { 105 res=invoke(pc, (Enumeration)obj, udf,execute,futures); 106 } 107 // String List 108 else if(obj instanceof StringListData) { 109 res=invoke(pc, (StringListData)obj, udf,execute,futures); 110 } 111 else 112 throw new FunctionException(pc, "Some", 1, "data", "cannot iterate througth this type "+Caster.toTypeName(obj.getClass())); 113 114 if(parallel) res=afterCall(pc,futures,execute); 115 116 return res; 117 } 118 119 private static boolean invoke(PageContext pc, Query qry, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 120 final int pid=pc.getId(); 121 ForEachQueryIterator it=new ForEachQueryIterator(qry, pid); 122 boolean async=es!=null; 123 double r; 124 Object res,row; 125 try{ 126 while(it.hasNext()){ 127 row=it.next(); 128 r = Caster.toDoubleValue(qry.getCurrentrow(pid)); 129 res=_inv(pc, udf, new Object[]{row,r,qry},r,row, es, futures); 130 if(!async && Caster.toBooleanValue(res)) { 131 return true; 132 } 133 } 134 } 135 finally { 136 it.reset(); 137 } 138 return false; 139 } 140 141 private static boolean invoke(PageContext pc, Array arr, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 142 Iterator<Entry<Key, Object>> it = arr.entryIterator(); 143 Entry<Key, Object> e; 144 boolean async=es!=null; 145 Object res; 146 while(it.hasNext()){ 147 e = it.next(); 148 res=_inv(pc, udf, new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),arr},e.getKey(),e.getValue(), es, futures); 149 if(!async && Caster.toBooleanValue(res)) { 150 return true; 151 } 152 } 153 return false; 154 } 155 156 private static boolean invoke(PageContext pc, StringListData sld, UDF udf, ExecutorService es, List<Future<Data<Object>>> futures) throws CasterException, PageException { 157 Array arr = ListUtil.listToArray(sld.list, sld.delimiter,sld.includeEmptyFieldsx,sld.multiCharacterDelimiter); 158 159 Iterator<Entry<Key, Object>> it = arr.entryIterator(); 160 Entry<Key, Object> e; 161 boolean async=es!=null; 162 Object res; 163 while(it.hasNext()){ 164 e = it.next(); 165 res=_inv(pc, udf, new Object[]{e.getValue(),Caster.toDoubleValue(e.getKey().getString()),sld.list,sld.delimiter},e.getKey(),e.getValue(), es, futures); 166 if(!async && Caster.toBooleanValue(res)) { 167 return true; 168 } 169 } 170 return false; 171 } 172 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 true; 188 } 189 return false; 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 true; 201 } 202 return false; 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 true; 214 } 215 return false; 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 true; 228 } 229 return false; 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 true; 244 } 245 return false; 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 true; 260 } 261 return false; 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 true; 279 pc.write(d.output); 280 } 281 return false; 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 if(args.length==2) 294 return call(pc, Caster.toStruct(args[0]), Caster.toFunction(args[1])); 295 if(args.length==3) 296 return call(pc, Caster.toStruct(args[0]), Caster.toFunction(args[1]), Caster.toBooleanValue(args[2])); 297 if(args.length==4) 298 return call(pc, Caster.toStruct(args[0]), Caster.toFunction(args[1]), Caster.toBooleanValue(args[2]), Caster.toDoubleValue(args[3])); 299 300 throw new FunctionException(pc,"Some",2,4,args.length); 301 302 } 303 304}