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    }