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.util;
020
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024
025import lucee.commons.lang.CFTypes;
026import lucee.commons.lang.ExceptionUtil;
027import lucee.commons.lang.StringUtil;
028import lucee.runtime.PageContext;
029import lucee.runtime.exp.ExpressionException;
030import lucee.runtime.exp.PageException;
031import lucee.runtime.op.Caster;
032import lucee.runtime.op.Decision;
033import lucee.runtime.reflection.Reflector;
034import lucee.runtime.security.SecurityManager;
035import lucee.runtime.text.xml.XMLUtil;
036import lucee.runtime.text.xml.struct.XMLStructFactory;
037import lucee.runtime.type.Collection;
038import lucee.runtime.type.Collection.Key;
039import lucee.runtime.type.FunctionValue;
040import lucee.runtime.type.KeyImpl;
041import lucee.runtime.type.Objects;
042import lucee.runtime.type.Query;
043import lucee.runtime.type.QueryColumn;
044import lucee.runtime.type.Struct;
045import lucee.runtime.type.UDFPlus;
046import lucee.runtime.type.scope.Undefined;
047import lucee.runtime.type.util.ArrayUtil;
048import lucee.runtime.type.util.KeyConstants;
049import lucee.runtime.type.util.MemberUtil;
050import lucee.runtime.type.util.Type;
051import lucee.runtime.type.wrap.MapAsStruct;
052
053import org.w3c.dom.Node;
054
055/**
056 * Class to handle CF Variables (set,get,call)
057 */
058public final class VariableUtilImpl implements VariableUtil {
059
060    @Override
061        public Object getCollection(PageContext pc, Object coll, String key, Object defaultValue) {
062        if(coll instanceof Query) {
063                // TODO sollte nicht null sein
064            return ((Query)coll).getColumn(key,null);
065        }
066        return get(pc,coll,key,defaultValue);
067    }
068    
069    public Object getCollection(PageContext pc, Object coll, Collection.Key key, Object defaultValue) {// FUTURE add to interface
070        if(coll instanceof Query) {
071                QueryColumn qc = ((Query)coll).getColumn(key,null);
072                if(qc==null) return defaultValue;
073                return qc;
074        }
075        return get(pc,coll,key,defaultValue);
076    }
077
078    @Override
079        public Object get(PageContext pc, Object coll, String key, Object defaultValue) {
080        // Objects
081        if(coll instanceof Objects) {
082            return ((Objects)coll).get(pc,KeyImpl.init(key),defaultValue);
083        }
084                // Collection
085        else if(coll instanceof Collection) {
086            return ((Collection)coll).get(key,defaultValue);
087        } 
088                // Map
089                else if(coll instanceof Map) {
090                        Object rtn=((Map)coll).get(key);
091                        //if(rtn==null)rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
092                        if(rtn!=null) return rtn;
093                        return defaultValue;
094                } 
095                // List
096                else if(coll instanceof List) {
097                        int index=Caster.toIntValue(key,Integer.MIN_VALUE);
098                    if(index==Integer.MIN_VALUE) return defaultValue;
099                    try {
100                        return ((List)coll).get(index-1);
101                    }
102                    catch(IndexOutOfBoundsException e) {
103                        return defaultValue;
104                    }
105                }
106                // Native Array
107                else if(Decision.isNativeArray(coll)) {
108                        return ArrayUtil.get(coll,Caster.toIntValue(key,Integer.MIN_VALUE)-1,defaultValue);
109                }
110                // Node
111                else if(coll instanceof Node) {
112                    return XMLStructFactory.newInstance((Node)coll,false).get(key,defaultValue);
113                }
114        // Direct Object Access
115        if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
116                        return Reflector.getProperty(coll,key,defaultValue);
117                }
118                return null;
119                
120        }
121        
122    
123    @Override
124        public Object get(PageContext pc, Object coll, Collection.Key key, Object defaultValue) {
125        // Objects
126                //print.out("key:"+key.getString());
127                if(coll instanceof Objects) {
128            return ((Objects)coll).get(pc,key,defaultValue);
129        }
130                // Collection
131        else if(coll instanceof Collection) {
132            return ((Collection)coll).get(key,defaultValue);
133        } 
134                // Map
135                else if(coll instanceof Map) {
136                        
137                        Object rtn=((Map)coll).get(key.getString());
138                        //if(rtn==null)rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key.getString()));
139                        if(rtn!=null) return rtn;
140                        return defaultValue;
141                        
142                } 
143                // List
144                else if(coll instanceof List) {
145                        int index=Caster.toIntValue(key,Integer.MIN_VALUE);
146                    if(index==Integer.MIN_VALUE) return defaultValue;
147                    try {
148                        return ((List)coll).get(index-1);
149                    }
150                    catch(IndexOutOfBoundsException e) {
151                        return defaultValue;
152                    }
153                }
154                // Native Array
155                else if(Decision.isNativeArray(coll)) {
156                        return ArrayUtil.get(coll,Caster.toIntValue(key,Integer.MIN_VALUE)-1,defaultValue);
157                }
158                // Node
159                else if(coll instanceof Node) {
160                    return XMLStructFactory.newInstance((Node)coll,false).get(key,defaultValue);
161                }
162        // Direct Object Access
163        if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
164                        return Reflector.getProperty(coll,key.getString(),defaultValue);
165                }
166                return null;
167                
168        }
169        
170        public Object getLight(PageContext pc, Object coll, Collection.Key key, Object defaultValue) {
171        // Objects
172        if(coll instanceof Objects) {
173            return ((Objects)coll).get(pc,key,defaultValue);
174        }
175                // Collection
176        else if(coll instanceof Collection) {
177                        return ((Collection)coll).get(key,defaultValue);
178                } 
179                // Map
180                else if(coll instanceof Map) {
181                        //Object rtn=null;
182                        try {
183                                Object rtn=((Map)coll).get(key.getString());
184                                //if(rtn==null)rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key.getString()));
185                                if(rtn!=null) return rtn;
186                        }
187                        catch(Throwable t) {
188                                ExceptionUtil.rethrowIfNecessary(t);
189                        }
190                        return Reflector.getField(coll,key.getString(),defaultValue);
191                        //return rtn;
192                } 
193                // List
194                else if(coll instanceof List) {
195                        int index=Caster.toIntValue(key.getString(),Integer.MIN_VALUE);
196                    if(index==Integer.MIN_VALUE) return null;
197                    try {
198                        return ((List)coll).get(index-1);
199                    }
200                    catch(IndexOutOfBoundsException e) {
201                        return defaultValue;
202                    }
203                }
204                return defaultValue;
205        }
206        
207        @Override
208        public Object getLight(PageContext pc, Object coll, String key, Object defaultValue) {
209        // Objects
210        if(coll instanceof Objects) {
211            return ((Objects)coll).get(pc,KeyImpl.init(key),defaultValue);
212        }
213                // Collection
214        else if(coll instanceof Collection) {
215                        return ((Collection)coll).get(key,defaultValue);
216                } 
217                // Map
218                else if(coll instanceof Map) {
219                        try {
220                                Object rtn=((Map)coll).get(key);
221                                //if(rtn==null)rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
222                                if(rtn!=null) return rtn;
223                        }
224                        catch(Throwable t) {
225                                ExceptionUtil.rethrowIfNecessary(t);
226                        }
227                        return Reflector.getProperty(coll,key,defaultValue);
228                        //return rtn;
229                } 
230                // List
231                else if(coll instanceof List) {
232                        int index=Caster.toIntValue(key,Integer.MIN_VALUE);
233                    if(index==Integer.MIN_VALUE) return null;
234                    try {
235                        return ((List)coll).get(index-1);
236                    }
237                    catch(IndexOutOfBoundsException e) {
238                        return defaultValue;
239                    }
240                }
241                return defaultValue;
242        }
243        
244        @Override
245        public Object getCollection(PageContext pc, Object coll, String key) throws PageException {
246        if(coll instanceof Query) {
247            return ((Query)coll).getColumn(key);
248        }
249        return get(pc,coll,key);
250    }
251    public Object getCollection(PageContext pc, Object coll, Collection.Key key) throws PageException {
252        if(coll instanceof Query) {
253            return ((Query)coll).getColumn(key);
254        }
255        return get(pc,coll,key);
256    }
257    
258    public Object get(PageContext pc, Object coll, Collection.Key key) throws PageException {
259        // Objects
260        if(coll instanceof Objects) {
261            return ((Objects)coll).get(pc,key);
262        }
263        // Collection
264        else if(coll instanceof Collection) {
265            return ((Collection)coll).get(key);
266                } 
267                // Map
268                else if(coll instanceof Map) {
269                        Object rtn=null;
270                        try {
271                                rtn=((Map)coll).get(key.getString());
272                                if(rtn==null && coll.getClass().getName().startsWith("org.hibernate."))
273                                        rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key.getString()));
274                                if(rtn!=null) return rtn;
275                        }
276                        catch(Throwable t) {
277                                ExceptionUtil.rethrowIfNecessary(t);
278                        }
279                        rtn = Reflector.getProperty(coll,key.getString(),null);
280                        if(rtn!=null) return rtn;
281                        
282                        String realKey = MapAsStruct.getCaseSensitiveKey((Map)coll, key.getString());
283                        String detail=null;
284                        if(realKey!=null) {
285                                detail="The keys for this Map are case-sensitive, use bracked notation like this \"map['"+realKey+"']\" instead of dot notation like this  \"map."+realKey+"\" to address the Map";
286                        }
287                        
288                        throw new ExpressionException("Key ["+key.getString()+"] doesn't exist in Map ("+((Map)coll).getClass().getName()+")",detail);
289                } 
290                // List
291                else if(coll instanceof List) {
292                    try {
293                        Object rtn=((List)coll).get(Caster.toIntValue(key.getString())-1);
294                        if(rtn==null) throw new ExpressionException("Key ["+key.getString()+"] doesn't exist in List");
295                                return rtn;
296                    }
297                    catch(IndexOutOfBoundsException e) {
298                        throw new ExpressionException("Key ["+key.getString()+"] doesn't exist in List");
299                    }
300                }
301                // Native Array
302                else if(Decision.isNativeArray(coll)) {
303                        Object rtn=ArrayUtil.get(coll,Caster.toIntValue(key.getString())-1,null);
304                        if(rtn==null) throw new ExpressionException("Key ["+key.getString()+"] doesn't exist in Native Array");
305                        return rtn;
306                }
307        // Node
308                else if(coll instanceof Node) {
309                        //print.out("get:"+key);
310            return XMLStructFactory.newInstance((Node)coll,false).get(key);
311        }
312                else if(coll instanceof String) {
313                        if(Decision.isInteger(key.getString())) { // i do the decision call and the caster call, because in most cases the if will be false
314                                String str=(String)coll;
315                                int index = Caster.toIntValue(key.getString(),-1);
316                                if(index>0 && index<=str.length()) {
317                                        return str.substring(index-1,index);
318                                }
319                        }
320                }
321        // HTTPSession
322                /*else if(coll instanceof HttpSession) {
323            return ((HttpSession)coll).getAttribute(key.getString());
324        }*/
325        
326        
327        
328        // Direct Object Access
329                if(coll!=null && pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
330                        return Reflector.getProperty(coll,key.getString());
331                }
332                throw new ExpressionException("No matching property ["+key.getString()+"] found");
333        
334    }
335    
336    @Override
337        public Object get(PageContext pc, Object coll, String key) throws PageException {
338        // Objects
339        if(coll instanceof Objects) {
340            return ((Objects)coll).get(pc,KeyImpl.init(key));
341        }
342        // Collection
343        else if(coll instanceof Collection) {
344            
345                        return ((Collection)coll).get(KeyImpl.init(key));
346                } 
347                // Map
348                else if(coll instanceof Map) {
349                        Object rtn=null;
350                        try {
351                                rtn=((Map)coll).get(key);
352                                //if(rtn==null)rtn=((Map)coll).get(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
353                                if(rtn!=null) return rtn;
354                                
355                        }
356                        catch(Throwable t) {
357                                ExceptionUtil.rethrowIfNecessary(t);
358                        }
359                        rtn = Reflector.getProperty(coll,key,null);
360                        if(rtn!=null) return rtn;
361                        throw new ExpressionException("Key ["+key+"] doesn't exist in Map ("+Caster.toClassName(coll)+")","keys are ["+keyList(((Map)coll))+"]");
362                } 
363                // List
364                else if(coll instanceof List) {
365                    try {
366                        Object rtn=((List)coll).get(Caster.toIntValue(key)-1);
367                        if(rtn==null) throw new ExpressionException("Key ["+key+"] doesn't exist in List");
368                                return rtn;
369                    }
370                    catch(IndexOutOfBoundsException e) {
371                        throw new ExpressionException("Key ["+key+"] doesn't exist in List");
372                    }
373                }
374                // Native Array
375                else if(Decision.isNativeArray(coll)) {
376                        Object rtn=ArrayUtil.get(coll,Caster.toIntValue(key)-1,null);
377                        if(rtn==null) throw new ExpressionException("Key ["+key+"] doesn't exist in Native Array");
378                        return rtn;
379                }
380        // Node
381        else if(coll instanceof Node) {
382            return XMLStructFactory.newInstance((Node)coll,false).get(key);
383        }
384        // Direct Object Access
385                if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
386                        return Reflector.getProperty(coll,key);
387                }
388                throw new ExpressionException("No matching property ["+key+"] found");
389        
390    }
391
392
393    private String keyList(Map map) {
394        StringBuffer sb=new StringBuffer();
395                Iterator it = map.keySet().iterator();
396                while(it.hasNext()) {
397                        if(sb.length()>0)sb.append(',');
398                        sb.append(StringUtil.toStringNative(it.next(),""));
399                }
400                return sb.toString();
401        }
402
403        public Object set(PageContext pc, Object coll, Collection.Key key,Object value) throws PageException {
404        // Objects
405        if(coll instanceof Objects) { 
406            ((Objects)coll).set(pc,key,value);
407            return value;
408        }
409        // Collection
410        else if(coll instanceof Collection) { 
411            ((Collection)coll).set(key,value);
412            return value;
413        }
414                // Map
415                else if(coll instanceof Map) {
416                        ((Map)coll).put(key.getString(),value);
417                        return value;
418                } 
419                // List
420                else if(coll instanceof List) {
421                    List list=((List)coll);
422                    int index=Caster.toIntValue(key.getString());
423                    if(list.size()>=index)list.set(index-1,value);
424                    else {
425                        while(list.size()<index-1)list.add(null);
426                        list.add(value);
427                    }
428                        return value;
429                }
430                // Native Array
431                else if(Decision.isNativeArray(coll)) {
432                        try {
433                return ArrayUtil.set(coll,Caster.toIntValue(key.getString())-1,value);
434            } catch (Exception e) {
435                throw new ExpressionException("invalid index ["+key.getString()+"] for Native Array, can't expand Native Arrays");
436            }
437                }
438                // Node
439                else if(coll instanceof Node) {
440                        return XMLUtil.setProperty((Node)coll,key,value);
441                }
442        // Direct Object Access
443                if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
444                        try {
445                        Reflector.setProperty(coll,key.getString(),value);
446                        return value;
447                    }
448                    catch(PageException pe) {} 
449                }       
450                throw new ExpressionException("can't assign value to a Object of this type ["+Type.getName(coll)+"] with key "+key.getString());
451    }
452    
453    
454    /**
455     * @see lucee.runtime.util.VariableUtil#set(lucee.runtime.PageContext, java.lang.Object, java.lang.String, java.lang.Object)
456     */
457    public Object set(PageContext pc, Object coll, String key,Object value) throws PageException {
458        // Objects
459        if(coll instanceof Objects) { 
460            ((Objects)coll).set(pc,KeyImpl.init(key),value);
461            return value;
462        }
463        // Collection
464        else if(coll instanceof Collection) { 
465            ((Collection)coll).set(key,value);
466            return value;
467        }
468                // Map
469                else if(coll instanceof Map) {
470                        ((Map)coll).put(key,value);
471                        return value;
472                } 
473                // List
474                else if(coll instanceof List) {
475                    List list=((List)coll);
476                    int index=Caster.toIntValue(key);
477                    if(list.size()>=index)list.set(index-1,value);
478                    else {
479                        while(list.size()<index-1)list.add(null);
480                        list.add(value);
481                    }
482                        return value;
483                }
484                // Native Array
485                else if(Decision.isNativeArray(coll)) {
486                        try {
487                return ArrayUtil.set(coll,Caster.toIntValue(key)-1,value);
488            } catch (Exception e) {
489                throw new ExpressionException("invalid index ["+key+"] for Native Array, can't expand Native Arrays");
490            }
491                }
492                // Node
493                else if(coll instanceof Node) {
494                        return XMLUtil.setProperty((Node)coll,KeyImpl.init(key),value);
495                }
496        // Direct Object Access
497                if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
498                        try {
499                        Reflector.setProperty(coll,key,value);
500                        return value;
501                    }
502                    catch(PageException pe) {} 
503                }       
504                throw new ExpressionException("can't assign value to a Object of this type ["+Type.getName(coll)+"] with key "+key);
505    }
506    
507    /**
508     *
509     * @see lucee.runtime.util.VariableUtil#setEL(lucee.runtime.PageContext, java.lang.Object, java.lang.String, java.lang.Object)
510     */
511    public Object setEL(PageContext pc, Object coll, String key,Object value) {
512        // Objects
513        if(coll instanceof Objects) { 
514            ((Objects)coll).setEL(pc,KeyImpl.init(key),value);
515            return value;
516        }
517        // Collection
518        else if(coll instanceof Collection) { 
519                        ((Collection)coll).setEL(KeyImpl.init(key),value);
520                        return value;
521                }
522                // Map
523                else if(coll instanceof Map) {
524                        try {
525                                Reflector.setProperty(coll,key,value);
526                                return value;
527                        }
528                        catch(Throwable t) {
529                                ExceptionUtil.rethrowIfNecessary(t);
530                        }
531                        ((Map)coll).put(key,value);
532                        return value;
533                } 
534                // List
535                else if(coll instanceof List) {
536                    List list=((List)coll);
537                    int index=Caster.toIntValue(key,Integer.MIN_VALUE);
538                    if(index==Integer.MIN_VALUE) return null;
539                    if(list.size()>=index)list.set(index-1,value);
540                    else {
541                        while(list.size()<index-1)list.add(null);
542                        list.add(value);
543                    }
544                        return value;
545                }
546                // Native Array
547                else if(Decision.isNativeArray(coll)) {
548                        return ArrayUtil.setEL(coll,Caster.toIntValue(key,Integer.MIN_VALUE)-1,value);
549                }
550                // Node
551                else if(coll instanceof Node) {
552                        return XMLUtil.setPropertyEL((Node)coll,KeyImpl.init(key),value);
553                }
554        // Direct Object Access
555                if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
556                        Reflector.setPropertyEL(coll,key,value);
557                        return value; 
558                }
559                return null;
560    }
561    
562    /**
563     * @see lucee.runtime.util.VariableUtil#setEL(lucee.runtime.PageContext, java.lang.Object, lucee.runtime.type.Collection.Key, java.lang.Object)
564     */
565    public Object setEL(PageContext pc, Object coll, Collection.Key key,Object value) {
566        // Objects
567        if(coll instanceof Objects) { 
568            ((Objects)coll).setEL(pc,key,value);
569            return value;
570        }
571        // Collection
572        else if(coll instanceof Collection) { 
573                        ((Collection)coll).setEL(key,value);
574                        return value;
575                }
576                // Map
577                else if(coll instanceof Map) {
578                        try {
579                                Reflector.setProperty(coll,key.getString(),value);
580                                return value;
581                        }
582                        catch(Throwable t) {
583                                ExceptionUtil.rethrowIfNecessary(t);
584                        }
585                        ((Map)coll).put(key,value);
586                        return value;
587                } 
588                // List
589                else if(coll instanceof List) {
590                    List list=((List)coll);
591                    int index=Caster.toIntValue(key,Integer.MIN_VALUE);
592                    if(index==Integer.MIN_VALUE) return null;
593                    if(list.size()>=index)list.set(index-1,value);
594                    else {
595                        while(list.size()<index-1)list.add(null);
596                        list.add(value);
597                    }
598                        return value;
599                }
600                // Native Array
601                else if(Decision.isNativeArray(coll)) {
602                        return ArrayUtil.setEL(coll,Caster.toIntValue(key,Integer.MIN_VALUE)-1,value);
603                }
604                // Node
605                else if(coll instanceof Node) {
606                        return XMLUtil.setPropertyEL((Node)coll,key,value);
607                }
608        // Direct Object Access
609                if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
610                        Reflector.setPropertyEL(coll,key.getString(),value);
611                        return value; 
612                }
613                return null;
614    }
615
616    /**
617     *
618     * @see lucee.runtime.util.VariableUtil#removeEL(java.lang.Object, java.lang.String)
619     */
620    public Object removeEL(Object coll, String key) {
621        // Collection
622        if(coll instanceof Collection) { 
623                        return ((Collection)coll).removeEL(KeyImpl.init(key));
624                }
625                // Map
626                else if(coll instanceof Map) { 
627                        Object obj = ((Map)coll).remove(key);
628                        //if(obj==null)obj=((Map)coll).remove(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
629                        return obj;
630                }
631                // List
632                else if(coll instanceof List) {
633                    int i=Caster.toIntValue(key,Integer.MIN_VALUE);
634                    if(i==Integer.MIN_VALUE) return null;
635                    return ((List)coll).remove(i);
636                }
637                return null;
638    }
639    
640    public Object removeEL(Object coll, Collection.Key key) {
641        // Collection
642        if(coll instanceof Collection) { 
643                        return ((Collection)coll).removeEL(key);
644                }
645                // Map
646                else if(coll instanceof Map) { 
647                        Object obj = ((Map)coll).remove(key.getString());
648                        //if(obj==null)obj=((Map)coll).remove(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
649                        return obj;
650                }
651                // List
652                else if(coll instanceof List) {
653                    int i=Caster.toIntValue(key,Integer.MIN_VALUE);
654                    if(i==Integer.MIN_VALUE) return null;
655                    return ((List)coll).remove(i);
656                }
657                return null;
658    }
659    
660
661    /**
662     * @see lucee.runtime.util.VariableUtil#remove(java.lang.Object, java.lang.String)
663     */
664    public Object remove(Object coll, String key) throws PageException {
665        // Collection
666                if(coll instanceof Collection) { 
667                        return ((Collection)coll).remove(KeyImpl.init(key));
668                }
669                // Map
670                else if(coll instanceof Map) { 
671                        Object obj=((Map)coll).remove(key);
672                        //if(obj==null)obj=((Map)coll).remove(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
673                        if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from map");
674                        return obj;
675                }
676                // List
677                else if(coll instanceof List) {
678                    int i=Caster.toIntValue(key);
679                    Object obj=((List)coll).remove(i);
680                        if(obj==null) throw new ExpressionException("can't remove index ["+key+"] from list");
681                        return obj;
682                }
683                /*/ Native Array TODO this below
684                else if(Decision.isNativeArray(o)) {
685                        try {
686                                return ArrayUtil.set(o,Caster.toIntValue(key)-1,value);
687                        } catch (Exception e) {
688                                return getDirectProperty(o, key, new ExpressionException("Key doesn't exist in Native Array"),false);
689                        }
690                }*/
691                // TODO Support for Node
692                throw new ExpressionException("can't remove key ["+key+"] from Object of type ["+Caster.toTypeName(coll)+"]");
693    }
694    
695    public Object remove(Object coll, Collection.Key key) throws PageException {
696        // Collection
697                if(coll instanceof Collection) { 
698                        return ((Collection)coll).remove(key);
699                }
700                // Map
701                else if(coll instanceof Map) { 
702                        Object obj=((Map)coll).remove(key.getString());
703                        //if(obj==null)obj=((Map)coll).remove(MapAsStruct.getCaseSensitiveKey((Map)coll, key));
704                        if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from map");
705                        return obj;
706                }
707                // List
708                else if(coll instanceof List) {
709                    int i=Caster.toIntValue(key);
710                    Object obj=((List)coll).remove(i);
711                        if(obj==null) throw new ExpressionException("can't remove index ["+key+"] from list");
712                        return obj;
713                }
714                /*/ Native Array TODO this below
715                else if(Decision.isNativeArray(o)) {
716                        try {
717                                return ArrayUtil.set(o,Caster.toIntValue(key)-1,value);
718                        } catch (Exception e) {
719                                return getDirectProperty(o, key, new ExpressionException("Key doesn't exist in Native Array"),false);
720                        }
721                }*/
722                // TODO Support for Node
723                throw new ExpressionException("can't remove key ["+key+"] from Object of type ["+Caster.toTypeName(coll)+"]");
724    }
725    
726    /**
727     * @see lucee.runtime.util.VariableUtil#callFunction(lucee.runtime.PageContext, java.lang.Object, java.lang.String, java.lang.Object[])
728     */
729    public Object callFunction(PageContext pc, Object coll, String key, Object[] args) throws PageException {
730                if(args.length>0 && args[0] instanceof FunctionValue)
731                        return callFunctionWithNamedValues(pc, coll, key, args);
732                return callFunctionWithoutNamedValues(pc, coll, key, args);
733        }
734    
735    /**
736     * @see lucee.runtime.util.VariableUtil#callFunctionWithoutNamedValues(lucee.runtime.PageContext, java.lang.Object, java.lang.String, java.lang.Object[])
737     */
738        public Object callFunctionWithoutNamedValues(PageContext pc, Object coll, String key, Object[] args) throws PageException {
739            return callFunctionWithoutNamedValues(pc, coll, KeyImpl.init(key), args);
740        }
741        
742        public Object callFunctionWithoutNamedValues(PageContext pc, Object coll, Collection.Key key, Object[] args) throws PageException {
743                // Objects
744                if(coll instanceof Objects) {
745                return ((Objects)coll).call(pc,key,args);
746        }
747        // call UDF
748            Object prop=getLight(pc,coll,key,null);     
749            if(prop instanceof UDFPlus) {
750                return ((UDFPlus)prop).call(pc,key,args,false);
751                }
752            // Strings
753            if(coll instanceof String) {
754                        return MemberUtil.call(pc,coll,key,args, CFTypes.TYPE_STRING, "string");
755            }
756            
757        // call Object Wrapper      
758            if(pc.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==SecurityManager.VALUE_YES) {
759                if(!(coll instanceof Undefined))return Reflector.callMethod(coll,key,args);
760            }
761                throw new ExpressionException("No matching Method/Function for "+key+"("+Reflector.getDspMethods(Reflector.getClasses(args))+")");
762
763    
764        }
765        
766        /**
767     * @see lucee.runtime.util.VariableUtil#callFunctionWithNamedValues(lucee.runtime.PageContext, java.lang.Object, java.lang.String, java.lang.Object[])
768     */
769        public Object callFunctionWithNamedValues(PageContext pc, Object coll, String key, Object[] args) throws PageException {
770                return callFunctionWithNamedValues(pc, coll, KeyImpl.init(key), args);
771        }
772
773        public Object callFunctionWithNamedValues(PageContext pc, Object coll, Collection.Key key, Object[] args) throws PageException {
774                // Objects
775        if(coll instanceof Objects) {
776            return ((Objects)coll).callWithNamedValues(pc,key, Caster.toFunctionValues(args));
777        }
778        // call UDF
779                Object prop=getLight(pc,coll,key,null); 
780        if(prop instanceof UDFPlus)             {
781            return ((UDFPlus)prop).callWithNamedValues(pc,key,Caster.toFunctionValues(args),false);
782        }
783        
784        // Strings
785            if(coll instanceof String) {
786                        return MemberUtil.callWithNamedValues(pc,coll,key,Caster.toFunctionValues(args), CFTypes.TYPE_STRING, "string");
787            }
788            
789        
790        throw new ExpressionException("No matching Method/Function ["+key+"] for call with named arguments found ");
791        }
792
793        public Object callFunctionWithNamedValues(PageContext pc, Object coll, Collection.Key key, Struct args) throws PageException {
794                // Objects
795        if(coll instanceof Objects) {
796            return ((Objects)coll).callWithNamedValues(pc,key, args);
797        }
798        // call UDF
799                Object prop=getLight(pc,coll,key,null); 
800        if(prop instanceof UDFPlus)             {
801            return ((UDFPlus)prop).callWithNamedValues(pc,key,args,false);
802        }
803        throw new ExpressionException("No matching Method/Function for call with named arguments found");
804        }
805        
806        // used by generated bytecode
807        public static Object recordcount(PageContext pc,Object obj) throws PageException{
808                if(obj instanceof Query) return Caster.toDouble(((Query)obj).getRecordcount());
809                return pc.getCollection(obj, KeyConstants._RECORDCOUNT);
810        }
811        // used by generated bytecode
812        public static Object currentrow(PageContext pc,Object obj) throws PageException{
813                if(obj instanceof Query) return Caster.toDouble(((Query)obj).getCurrentrow(pc.getId()));
814                return pc.getCollection(obj, KeyConstants._CURRENTROW);
815        }
816        // used by generated bytecode
817        public static Object columnlist(PageContext pc,Object obj) throws PageException{
818                if(obj instanceof Query) {
819                        Key[] columnNames = ((Query)obj).getColumnNames();
820                        
821                        boolean upperCase=true;//((ConfigImpl)ThreadLocalPageContext.getConfig()).getDotNotationUpperCase();
822                        
823                        
824                        StringBuilder sb=new StringBuilder();
825                        for(int i=0;i<columnNames.length;i++) {
826                                if(i>0)sb.append(',');
827                                sb.append(upperCase?columnNames[i].getUpperString():columnNames[i].getString());
828                        }
829                        return sb.toString();
830                        
831                        
832                }
833                return pc.getCollection(obj, KeyConstants._COLUMNLIST);
834        }
835    
836}