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.type; 020 021import lucee.commons.lang.CFTypes; 022import lucee.commons.lang.StringUtil; 023import lucee.runtime.Component; 024import lucee.runtime.ComponentImpl; 025import lucee.runtime.Page; 026import lucee.runtime.PageContext; 027import lucee.runtime.PageContextImpl; 028import lucee.runtime.PageSource; 029import lucee.runtime.component.MemberSupport; 030import lucee.runtime.dump.DumpData; 031import lucee.runtime.dump.DumpProperties; 032import lucee.runtime.exp.DeprecatedException; 033import lucee.runtime.exp.ExpressionException; 034import lucee.runtime.exp.PageException; 035import lucee.runtime.exp.PageRuntimeException; 036import lucee.runtime.exp.UDFCasterException; 037import lucee.runtime.functions.decision.IsValid; 038import lucee.runtime.op.Caster; 039import lucee.runtime.op.Decision; 040import lucee.runtime.type.Collection.Key; 041import lucee.runtime.type.util.ComponentUtil; 042import lucee.runtime.type.util.KeyConstants; 043import lucee.runtime.type.util.UDFUtil; 044 045public abstract class UDFGSProperty extends MemberSupport implements UDFPlus { 046 047 private static final Collection.Key MIN_LENGTH = KeyImpl.intern("minLength"); 048 private static final Collection.Key MAX_LENGTH = KeyImpl.intern("maxLength"); 049 050 protected final FunctionArgument[] arguments; 051 protected final String name; 052 protected ComponentImpl component; 053 private UDFPropertiesImpl properties; 054 055 public UDFGSProperty(ComponentImpl component,String name,FunctionArgument[] arguments,short rtnType,String rtnFormat) { 056 super(Component.ACCESS_PUBLIC); 057 properties=new UDFPropertiesImpl( 058 component.getPageSource(), 059 arguments, 060 -1, 061 name, 062 rtnType, 063 rtnFormat, 064 false, 065 Component.ACCESS_PUBLIC, 066 true, 067 "", 068 "", 069 "", 070 Boolean.FALSE, 071 Boolean.FALSE, 072 null, 073 null, 074 null 075 076 ); 077 078 this.name=name; 079 this.arguments=arguments; 080 this.component=component; 081 } 082 083 084 @Override 085 public FunctionArgument[] getFunctionArguments() { 086 return arguments; 087 } 088 089 @Override 090 public String getFunctionName() { 091 return name; 092 } 093 094 @Override 095 public PageSource getPageSource() { 096 return component.getPageSource(); 097 } 098 099 @Override 100 public int getIndex() { 101 return -1; 102 } 103 104 @Override 105 public Component getOwnerComponent() { 106 return component; 107 } 108 109 public void setOwnerComponent(ComponentImpl component) { 110 this.component = component; 111 } 112 113 public Page getPage() { 114 throw new PageRuntimeException(new DeprecatedException("method getPage():Page is no longer suppoted, use instead getPageSource():PageSource")); 115 } 116 117 @Override 118 public boolean getOutput() { 119 return false; 120 } 121 122 public UDF duplicate(boolean deep) { 123 return duplicate(); // deep has no influence here, because a UDF is not a collection 124 } 125 126 @Override 127 public String getDisplayName() { 128 return ""; 129 } 130 131 @Override 132 public String getDescription() { 133 return ""; 134 } 135 136 @Override 137 public String getHint() { 138 return ""; 139 } 140 141 @Override 142 public int getReturnFormat() { 143 return UDF.RETURN_FORMAT_WDDX; 144 } 145 146 @Override 147 public int getReturnFormat(int defaultValue) { 148 return defaultValue; 149 } 150 151 @Override 152 public int getReturnType() { 153 return CFTypes.toShortStrict(getReturnTypeAsString(),CFTypes.TYPE_UNKNOW); 154 } 155 156 @Override 157 public Object getValue() { 158 return this; 159 } 160 161 @Override 162 public Boolean getSecureJson() { 163 return null; 164 } 165 166 @Override 167 public Boolean getVerifyClient() { 168 return null; 169 } 170 171 @Override 172 public DumpData toDumpData(PageContext pageContext, int maxlevel,DumpProperties properties) { 173 return UDFUtil.toDumpData(pageContext, maxlevel, properties, this,UDFUtil.TYPE_UDF); 174 } 175 176 @Override 177 public Struct getMetaData(PageContext pc) throws PageException { 178 return ComponentUtil.getMetaData(pc, properties); 179 } 180 181 182 183 final Object cast(PageContext pc,FunctionArgument arg,Object value, int index) throws PageException { 184 if(value==null || Decision.isCastableTo(pc,arg.getType(),arg.getTypeAsString(),value)) 185 return value; 186 throw new UDFCasterException(this,arg,value,index); 187 } 188 189 final static void validate(String validate, Struct validateParams, Object obj) throws PageException { 190 if(StringUtil.isEmpty(validate,true)) return; 191 validate=validate.trim().toLowerCase(); 192 193 if(!validate.equals("regex") && !Decision.isValid(validate, obj)) 194 throw new ExpressionException(createMessage(validate, obj)); 195 196 197 // range 198 if(validateParams==null) return; 199 200 if(validate.equals("integer") || validate.equals("numeric") || validate.equals("number")){ 201 double min=Caster.toDoubleValue(validateParams.get(KeyConstants._min,null),false,Double.NaN); 202 double max=Caster.toDoubleValue(validateParams.get(KeyConstants._max,null),false,Double.NaN); 203 double d=Caster.toDoubleValue(obj); 204 if(!Double.isNaN(min) && d<min) 205 throw new ExpressionException(validate+" ["+Caster.toString(d)+"] is out of range, value must be more than or equal to ["+min+"]"); 206 if(!Double.isNaN(max) && d>max) 207 throw new ExpressionException(validate+" ["+Caster.toString(d)+"] is out of range, value must be less than or equal to ["+max+"]"); 208 } 209 else if(validate.equals("string")){ 210 double min=Caster.toDoubleValue(validateParams.get(MIN_LENGTH,null),false,Double.NaN); 211 double max=Caster.toDoubleValue(validateParams.get(MAX_LENGTH,null),false,Double.NaN); 212 String str=Caster.toString(obj); 213 int l=str.length(); 214 if(!Double.isNaN(min) && l<((int)min)) 215 throw new ExpressionException("string ["+str+"] is to short ["+l+"], the string must be at least ["+min+"] characters"); 216 if(!Double.isNaN(max) && l>((int)max)) 217 throw new ExpressionException("string ["+str+"] is to long ["+l+"], the string can have a maximum length of ["+max+"] characters"); 218 } 219 else if(validate.equals("regex")){ 220 String pattern=Caster.toString(validateParams.get(KeyConstants._pattern,null),null); 221 String value=Caster.toString(obj); 222 if(!StringUtil.isEmpty(pattern,true) && !IsValid.regex(value, pattern)) 223 throw new ExpressionException("the string ["+value+"] does not match the regular expression pattern ["+pattern+"]"); 224 } 225 } 226 227 228 @Override 229 public Object callWithNamedValues(PageContext pc, Key calledName, Struct values, boolean doIncludePath) throws PageException { 230 PageContextImpl pci = ((PageContextImpl)pc); 231 Key old =pci.getActiveUDFCalledName(); 232 pci.setActiveUDFCalledName(calledName); 233 try{ 234 return callWithNamedValues(pci, values, doIncludePath); 235 } 236 finally{ 237 pci.setActiveUDFCalledName(old); 238 } 239 } 240 241 @Override 242 public Object call(PageContext pc, Key calledName, Object[] args, boolean doIncludePath) throws PageException { 243 PageContextImpl pci = ((PageContextImpl)pc); 244 Key old =pci.getActiveUDFCalledName(); 245 pci.setActiveUDFCalledName(calledName); 246 try{ 247 return call(pci, args, doIncludePath); 248 } 249 finally{ 250 pci.setActiveUDFCalledName(old); 251 } 252 } 253 254 private static String createMessage(String format, Object value) { 255 if(Decision.isSimpleValue(value)) return "the value ["+Caster.toString(value,null)+"] is not in ["+format+"] format"; 256 return "cannot convert object from type ["+Caster.toTypeName(value)+"] to a ["+format+"] format"; 257 } 258 259}