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