001    package railo.runtime.functions.decision;
002    
003    import org.apache.oro.text.regex.MalformedPatternException;
004    import org.apache.oro.text.regex.Pattern;
005    import org.apache.oro.text.regex.PatternMatcherInput;
006    import org.apache.oro.text.regex.Perl5Compiler;
007    import org.apache.oro.text.regex.Perl5Matcher;
008    
009    import railo.runtime.PageContext;
010    import railo.runtime.exp.ExpressionException;
011    import railo.runtime.exp.FunctionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.ext.function.Function;
014    import railo.runtime.op.Caster;
015    import railo.runtime.op.Decision;
016    
017    /**
018     * 
019     */
020    public final class IsValid implements Function {
021    
022            private static final long serialVersionUID = -1383105304624662986L;
023    
024            /**
025             * check for many diff types
026             * @param pc
027             * @param type
028             * @param value
029             * @return
030             * @throws ExpressionException
031             */
032            public static boolean call(PageContext pc, String type, Object value) throws ExpressionException {
033                    type=type.trim();
034    
035                    if("range".equalsIgnoreCase(type))
036                            throw new FunctionException(pc,"isValid",1,"type","for [range] you have to define a min and max value");
037    
038                    if("regex".equalsIgnoreCase(type) || "regular_expression".equalsIgnoreCase(type))
039                            throw new FunctionException(pc,"isValid",1,"type","for [regex] you have to define a pattern");
040    
041                    return Decision.isValid(type, value);
042            }
043            
044            /**
045             * regex check
046             * @param pc
047             * @param type
048             * @param value
049             * @param objPattern
050             * @return
051             * @throws PageException 
052             */
053            public static boolean call(PageContext pc, String type, Object value, Object objPattern) throws PageException {
054                    type=type.trim();
055    
056                    if(!"regex".equalsIgnoreCase(type) && !"regular_expression".equalsIgnoreCase(type))
057                            throw new FunctionException(pc,"isValid",1,"type","wrong attribute count for type ["+type+"]");
058                    
059                    return regex(Caster.toString(value,null),Caster.toString(objPattern));
060            }
061            
062            
063            
064            
065            public static boolean regex(String value,String strPattern) {
066                    if(value==null)
067                            return false;
068                    
069                    try {
070                            Pattern pattern = new Perl5Compiler().compile(strPattern, Perl5Compiler.MULTILINE_MASK);
071                    PatternMatcherInput input = new PatternMatcherInput(value);
072                    return new Perl5Matcher().matches(input, pattern);
073                    } catch (MalformedPatternException e) {
074                            return false;
075                    }
076            }
077    
078            public static boolean call(PageContext pc, String type, Object value, Object objMin, Object objMax) throws PageException {
079                    
080                    // for named argument calls
081                    if(objMax==null) {
082                            if(objMin==null) return call(pc, type, value);
083                            return call(pc, type, value, objMin);
084                    }
085                    
086                    type=type.trim().toLowerCase();
087                    
088                    // numeric
089                    if("range".equals(type) || "integer".equals(type) || "float".equals(type) || "numeric".equals(type)  || "number".equals(type) ) {
090                    
091                            double number=Caster.toDoubleValue(value,Double.NaN);
092                            if(!Decision.isValid(number)) return false;
093                            
094                            double min=toRangeNumber(pc,objMin,3,"min");
095                            double max=toRangeNumber(pc,objMax,4,"max");
096                            
097                            
098                            return number>=min && number<=max;
099                    }
100                    else if("string".equals(type)){
101                            String str=Caster.toString(value,null);
102                            if(str==null) return false;
103                            
104                            double min=toRangeNumber(pc,objMin,3,"min");
105                            double max=toRangeNumber(pc,objMax,4,"max");
106                            
107                            return str.length()>=min && str.length()<=max;
108                    }
109                    
110                    else
111                            throw new FunctionException(pc,"isValid",1,"type","wrong attribute count for type ["+type+"]");
112                            
113            }
114    
115            private static double toRangeNumber(PageContext pc,Object objMin, int index,String name) throws FunctionException {
116                    double d=Caster.toDoubleValue(objMin,Double.NaN);
117                    if(!Decision.isValid(d))
118                            throw new FunctionException(pc,"isValid",index,name,"value must be numeric");
119                    return d;
120            }
121    }