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 structfindkey 021 */ 022package lucee.runtime.functions.struct; 023 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028 029import lucee.runtime.PageContext; 030import lucee.runtime.exp.FunctionException; 031import lucee.runtime.exp.PageException; 032import lucee.runtime.functions.BIF; 033import lucee.runtime.op.Caster; 034import lucee.runtime.type.Array; 035import lucee.runtime.type.ArrayImpl; 036import lucee.runtime.type.Collection; 037import lucee.runtime.type.Collection.Key; 038import lucee.runtime.type.Struct; 039import lucee.runtime.type.StructImpl; 040import lucee.runtime.type.scope.Argument; 041import lucee.runtime.type.util.KeyConstants; 042import lucee.runtime.type.wrap.ListAsArray; 043import lucee.runtime.type.wrap.MapAsStruct; 044 045public final class StructFindKey extends BIF { 046 047 private static final long serialVersionUID = 598706098288773975L; 048 049 public static Array call(PageContext pc , lucee.runtime.type.Struct struct, String value) throws PageException { 050 return _call(pc,struct,value,false); 051 } 052 public static Array call(PageContext pc , Struct struct, String value, String scope) throws PageException { 053 // Scope 054 boolean all=false; 055 if(scope.equalsIgnoreCase("one")) all=false; 056 else if(scope.equalsIgnoreCase("all")) all=true; 057 else throw new FunctionException(pc,"structFindValue",3,"scope","invalid scope definition ["+scope+"], valid scopes are [one, all]"); 058 return _call(pc,struct,value,all); 059 } 060 private static Array _call(PageContext pc , Struct struct, String value, boolean all) throws PageException { 061 Array array=new ArrayImpl(); 062 getValues(array,struct,value,all,""); 063 return array; 064 } 065 /** 066 * @param coll 067 * @param value 068 * @param all 069 * @param buffer 070 * @return 071 * @throws PageException 072 */ 073 private static boolean getValues(Array array,Collection coll, String value, boolean all, String path) throws PageException { 074 //Collection.Key[] keys=coll.keys(); 075 Iterator<Entry<Key, Object>> it = coll.entryIterator(); 076 Entry<Key, Object> e; 077 boolean abort=false; 078 Collection.Key key; 079 080 while(it.hasNext()) { 081 e = it.next(); 082 if(abort)break; 083 key=e.getKey(); 084 Object o=e.getValue(); 085 086 // matching value (this function search first for base) 087 if(key.getString().equalsIgnoreCase(value)) { 088 Struct sct=new StructImpl(); 089 090 sct.setEL(KeyConstants._value,o); 091 sct.setEL(KeyConstants._path,createKey(coll,path,key)); 092 sct.setEL(KeyConstants._owner,coll); 093 array.append(sct); 094 if(!all)abort=true; 095 } 096 097 // Collection 098 if(!abort) { 099 if(o instanceof Collection) { 100 abort=getValues(array,((Collection)o), value, all, createKey(coll,path,key)); 101 } 102 else if(o instanceof List){ 103 abort=getValues(array,ListAsArray.toArray((List<?>)o), value, all, createKey(coll,path,key)); 104 } 105 else if(o instanceof Map){ 106 abort=getValues(array,MapAsStruct.toStruct((Map<?,?>)o), value, all, createKey(coll,path,key)); 107 } 108 } 109 } 110 111 return abort; 112 } 113 static String createKey(Collection coll,String path,Collection.Key key) { 114 StringBuilder p=new StringBuilder(path.toString()); 115 if(isArray(coll)){ 116 p.append('[').append(key.getString()).append(']'); 117 } 118 else{ 119 p.append('.').append(key.getString()); 120 } 121 return p.toString(); 122 } 123 static boolean isArray(Collection coll) { 124 return coll instanceof Array && !(coll instanceof Argument); 125 } 126 @Override 127 public Object invoke(PageContext pc, Object[] args) throws PageException { 128 if(args.length==3) return call(pc,Caster.toStruct(args[0]),Caster.toString(args[1]),Caster.toString(args[2])); 129 return call(pc,Caster.toStruct(args[0]),Caster.toString(args[1])); 130 } 131}