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}