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