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 dump 021 */ 022package lucee.runtime.functions.other; 023 024import java.util.Set; 025 026import lucee.commons.digest.HashUtil; 027import lucee.commons.lang.ExceptionUtil; 028import lucee.commons.lang.StringUtil; 029import lucee.commons.lang.types.RefBoolean; 030import lucee.commons.lang.types.RefBooleanImpl; 031import lucee.runtime.ComponentImpl; 032import lucee.runtime.PageContext; 033import lucee.runtime.dump.DumpData; 034import lucee.runtime.dump.DumpProperties; 035import lucee.runtime.dump.DumpRow; 036import lucee.runtime.dump.DumpTable; 037import lucee.runtime.dump.DumpUtil; 038import lucee.runtime.dump.SimpleDumpData; 039import lucee.runtime.ext.function.Function; 040import lucee.runtime.functions.string.Len; 041import lucee.runtime.op.Caster; 042import lucee.runtime.op.Decision; 043import lucee.runtime.type.Collection; 044import lucee.runtime.type.Collection.Key; 045import lucee.runtime.type.KeyImpl; 046import lucee.runtime.type.Query; 047import lucee.runtime.type.QueryImpl; 048import lucee.runtime.type.Struct; 049import lucee.runtime.type.StructImpl; 050import lucee.runtime.type.scope.Scope; 051import lucee.runtime.type.util.KeyConstants; 052import lucee.runtime.type.util.ListUtil; 053import lucee.runtime.type.util.StructUtil; 054 055public final class DumpStruct implements Function { 056 057 public static Struct call(PageContext pc , Object object) { 058 return call(pc, object,9999,null,null,9999,true); 059 } 060 061 public static Struct call(PageContext pc , Object object, double maxLevel) { 062 return call(pc, object,maxLevel,null,null,9999,true,true,null); 063 } 064 065 public static Struct call(PageContext pc , Object object, double maxLevel, String show) { 066 return call(pc, object,maxLevel,show,null,9999,true,true,null); 067 } 068 069 public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide) { 070 return call(pc,object,maxLevel,show,hide,9999,true,true,null); 071 } 072 073 public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys) { 074 return call(pc , object, maxLevel, show, hide,keys,true,true,null); 075 } 076 public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys,boolean metainfo) { 077 return call(pc , object, maxLevel, show, hide,keys,metainfo,true,null); 078 } 079 080 public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys,boolean metainfo, boolean showUDFs) { 081 return call(pc , object, maxLevel, show, hide,keys,metainfo,showUDFs,null); 082 } 083 084 public static Struct call(PageContext pc,Object object,double maxLevel, String show, String hide,double keys,boolean metainfo, boolean showUDFs, String label) { 085 if(show!=null && "all".equalsIgnoreCase(show.trim()))show=null; 086 if(hide!=null && "all".equalsIgnoreCase(hide.trim()))hide=null; 087 088 Set setShow=(show!=null)?ListUtil.listToSet(show.toLowerCase(),",",true):null; 089 Set setHide=(hide!=null)?ListUtil.listToSet(hide.toLowerCase(),",",true):null; 090 091 DumpProperties properties=new DumpProperties((int)maxLevel,setShow,setHide,(int)keys,metainfo,showUDFs); 092 DumpData dd = DumpUtil.toDumpData(object, pc,(int)maxLevel,properties); 093 094 if(!StringUtil.isEmpty(label)) { 095 DumpTable table=new DumpTable("#ffffff","#cccccc","#000000"); 096 table.appendRow(1,new SimpleDumpData(label)); 097 table.appendRow(0,dd); 098 dd=table; 099 } 100 RefBoolean hasReference=new RefBooleanImpl(false); 101 Struct sct = toStruct(dd,object,hasReference); 102 sct.setEL("hasReference", hasReference.toBoolean()); 103 104 addMetaData(sct, object); 105 106 return sct; 107 } 108 109 private static void addMetaData(Struct sct, Object o) { 110 111 String simpleType = "unknown"; // simpleType will replace colorId and colors 112 String simpleValue = ""; 113 114 try { 115 116 if (o == null) { 117 simpleType = "null"; 118 } 119 else if (o instanceof Scope) { 120 simpleType = "struct"; 121 simpleValue = "Scope (" + getSize(o) + ")"; 122 } 123 else if (Decision.isQuery(o)) { 124 simpleType = "query"; 125 simpleValue = "Query (" + getSize(o) + ")"; 126 } 127 else if (Decision.isComponent(o)) { 128 simpleType = "component"; 129 simpleValue = "Component: " + ((ComponentImpl)o).getDisplayName(); 130 } 131 else if (Decision.isFunction(o) || Decision.isUserDefinedFunction(o) || Decision.isClosure(o)) { 132 simpleType = "function"; 133// simpleValue = "Function: " + ((Function)o).(); // TODO: add signature 134 } 135 else if (Decision.isStruct(o)) { 136 simpleType = "struct"; 137 simpleValue = "Struct (" + getSize(o) + ")"; 138 } 139 else if (Decision.isArray(o)) { 140 simpleType = "array"; 141 simpleValue = "Array (" + getSize(o) + ")"; 142 } 143 else if (Decision.isDate(o, false)) { 144 simpleType = "date"; 145 simpleValue = o.toString(); 146 } 147 else if (Decision.isBoolean(o, false)) { 148 simpleType = "boolean"; 149 simpleValue = o.toString(); 150 } 151 else if (Decision.isInteger(o, false)) { 152 simpleType = "numeric"; 153 simpleValue = Caster.toInteger(o).toString(); 154 } 155 else if (Decision.isNumeric(o, false)) { 156 simpleType = "numeric"; 157 simpleValue = o.toString(); 158 } 159 else if (Decision.isSimpleValue(o)) { 160 simpleType = "string"; 161 simpleValue = Caster.toString(o); 162 if (simpleValue.length() > 64) 163 simpleValue = "String (" + simpleValue.length() + ")"; 164 } 165 else { 166 simpleType = o.getClass().getSimpleName().toLowerCase(); 167 } 168 169 } 170 catch (Throwable t) { 171 ExceptionUtil.rethrowIfNecessary(t); 172 simpleValue = "{error}"; 173 } 174 175 sct.setEL("simpleType", simpleType); 176 sct.setEL("simpleValue", simpleValue); 177 } 178 179 private static String getSize(Object o) { 180 181 return Caster.toInteger( Len.invoke(o, 0) ).toString(); 182 } 183 184 private static Struct toStruct(DumpData dd, Object object, RefBoolean hasReference) { 185 DumpTable table; 186 if(dd instanceof DumpTable) table=(DumpTable) dd; 187 else { 188 if(dd==null) dd= new SimpleDumpData("null"); 189 table=new DumpTable("#ffffff","#cccccc","#000000"); 190 table.appendRow(1,dd); 191 } 192 return toCFML(table,object,hasReference,null); 193 } 194 195 196 private static Object toCFML(DumpData dd, Object object, RefBoolean hasReference, Struct colors) { 197 if(dd instanceof DumpTable)return toCFML((DumpTable) dd,object,hasReference,colors); 198 if(dd==null) return new SimpleDumpData("null"); 199 return dd.toString(); 200 } 201 202 private static Struct toCFML(DumpTable dt, Object object, RefBoolean hasReference, Struct colors) { 203 204 Struct sct=new StructImpl(); 205 if(colors==null) { 206 colors=new StructImpl(); 207 sct.setEL("colors", colors); 208 } 209 Collection.Key type; 210 if(dt.getType()!=null) type=KeyImpl.init(dt.getType()); 211 else if(object!=null) type=KeyImpl.init(object.getClass().getName()); 212 else type=KeyConstants._null; 213 214 // colors 215 String borderColor = toShortColor(dt.getBorderColor()); 216 String fontColor = toShortColor(dt.getFontColor()); 217 String highLightColor = toShortColor(dt.getHighLightColor()); 218 String normalColor = toShortColor(dt.getNormalColor()); 219 // create color id 220 Key colorId = KeyImpl.init(Long.toString(HashUtil.create64BitHash(new StringBuilder(borderColor) 221 .append(':').append(fontColor) 222 .append(':').append(highLightColor) 223 .append(':').append(normalColor)),Character.MAX_RADIX)); 224 225 226 if(!colors.containsKey(colorId)) { 227 Struct color=new StructImpl(); 228 StructUtil.setELIgnoreWhenNull(color,"borderColor", borderColor); 229 StructUtil.setELIgnoreWhenNull(color,"fontColor", fontColor); 230 StructUtil.setELIgnoreWhenNull(color,"highLightColor", highLightColor); 231 StructUtil.setELIgnoreWhenNull(color,"normalColor", normalColor); 232 colors.setEL(colorId, color); 233 } 234 235 236 /*StructUtil.setELIgnoreWhenNull(sct,"borderColor", borderColor); 237 StructUtil.setELIgnoreWhenNull(sct,"fontColor", fontColor); 238 StructUtil.setELIgnoreWhenNull(sct,"highLightColor", highLightColor); 239 StructUtil.setELIgnoreWhenNull(sct,"normalColor", normalColor); 240 */ 241 StructUtil.setELIgnoreWhenNull(sct,"colorId", colorId.getString()); 242 StructUtil.setELIgnoreWhenNull(sct,KeyConstants._comment, dt.getComment()); 243 StructUtil.setELIgnoreWhenNull(sct,KeyConstants._height, dt.getHeight()); 244 StructUtil.setELIgnoreWhenNull(sct,KeyConstants._width, dt.getWidth()); 245 StructUtil.setELIgnoreWhenNull(sct,KeyConstants._title, dt.getTitle()); 246 247 sct.setEL(KeyConstants._type, type.getString()); 248 if(!StringUtil.isEmpty(dt.getId()))sct.setEL(KeyConstants._id, dt.getId()); 249 250 if("ref".equals(dt.getType())){ 251 hasReference.setValue(true); 252 sct.setEL(KeyConstants._ref, dt.getRef()); 253 } 254 255 256 DumpRow[] drs = dt.getRows(); 257 DumpRow dr; 258 Query qry=null; 259 DumpData[] items; 260 for(int r=0;r<drs.length;r++){ 261 dr=drs[r]; 262 items = dr.getItems(); 263 if(qry==null)qry=new QueryImpl(toColumns(items),drs.length,"data"); 264 for(int c=1;c<=items.length;c++){ 265 qry.setAtEL("data"+c, r+1, toCFML(items[c-1],object,hasReference,colors)); 266 } 267 qry.setAtEL("highlight", r+1, new Double(dr.getHighlightType())); 268 269 } 270 if(qry!=null)sct.setEL(KeyConstants._data, qry); 271 return sct; 272 } 273 274 private static String[] toColumns(DumpData[] items) { 275 String[] columns=new String[items.length+1]; 276 columns[0]="highlight"; 277 for(int i=1;i<columns.length;i++){ 278 columns[i]="data"+i; 279 } 280 return columns; 281 } 282 283 private static String toShortColor(String color) { 284 if(color!=null && color.length()==7 && color.startsWith("#")) { 285 if(color.charAt(1)==color.charAt(2) && color.charAt(3)==color.charAt(4) && color.charAt(5)==color.charAt(6)) 286 return "#"+color.charAt(1)+color.charAt(3)+color.charAt(5); 287 288 289 } 290 291 292 return color; 293 } 294}