001    package railo.runtime.op;
002    
003    import java.io.ByteArrayOutputStream;
004    import java.io.InputStream;
005    import java.sql.Blob;
006    import java.sql.Clob;
007    import java.text.DateFormat;
008    import java.text.ParseException;
009    import java.util.Calendar;
010    import java.util.Date;
011    import java.util.Iterator;
012    import java.util.List;
013    import java.util.Locale;
014    import java.util.Map;
015    import java.util.TimeZone;
016    import java.util.regex.Pattern;
017    
018    import org.w3c.dom.Document;
019    import org.w3c.dom.Element;
020    import org.w3c.dom.Node;
021    import org.w3c.dom.NodeList;
022    
023    import railo.commons.date.DateTimeUtil;
024    import railo.commons.date.JREDateTimeUtil;
025    import railo.commons.i18n.FormatUtil;
026    import railo.commons.lang.CFTypes;
027    import railo.commons.lang.StringUtil;
028    import railo.runtime.Component;
029    import railo.runtime.coder.Base64Util;
030    import railo.runtime.converter.WDDXConverter;
031    import railo.runtime.engine.ThreadLocalPageContext;
032    import railo.runtime.exp.ExpressionException;
033    import railo.runtime.exp.PageException;
034    import railo.runtime.ext.function.Function;
035    import railo.runtime.java.JavaObject;
036    import railo.runtime.op.date.DateCaster;
037    import railo.runtime.op.validators.ValidateCreditCard;
038    import railo.runtime.text.xml.XMLCaster;
039    import railo.runtime.text.xml.XMLUtil;
040    import railo.runtime.text.xml.struct.XMLStruct;
041    import railo.runtime.type.Array;
042    import railo.runtime.type.Collection;
043    import railo.runtime.type.ObjectWrap;
044    import railo.runtime.type.Objects;
045    import railo.runtime.type.Query;
046    import railo.runtime.type.Struct;
047    import railo.runtime.type.UDF;
048    import railo.runtime.type.dt.DateTime;
049    
050    
051    /**
052     * Object to test if a Object is a specific type
053     */
054    public final class Decision {
055    
056            private static final String STRING_DEFAULT_VALUE = "this is a unique string";
057            
058            private static Pattern emailPattern; 
059            private static Pattern ssnPattern;
060            private static Pattern phonePattern;
061            private static Pattern urlPattern;
062            private static Pattern zipPattern; 
063    
064            /**
065             * tests if value is a simple value (Number,String,Boolean,Date,Printable)
066             * @param value value to test
067             * @return is value a simple value
068             */
069            public static boolean isSimpleValue(Object value){
070                    return 
071                                    (value instanceof Number) || 
072                                    (value instanceof String) || 
073                                    (value instanceof Boolean) || 
074                                    (value instanceof Date) || 
075                                    ((value instanceof Castable) && !(value instanceof Objects) && !(value instanceof Collection));
076            }
077            
078            /**
079             * tests if value is Numeric
080             * @param value value to test
081             * @return is value numeric
082             */
083            public static boolean isNumeric(Object value) {
084                    if(value instanceof Number) return true;
085                    else if(value instanceof String) {
086                            return isNumeric(value.toString());
087                    }
088                    
089                    else return false;
090            }
091    
092            public static boolean isCastableToNumeric(Object o) {
093                    
094                    if(isNumeric(o)) return true;
095                    else if(isBoolean(o)) return true;
096                    else if(isDateSimple(o,false)) return true;
097            else if(o == null) return true;
098            else if(o instanceof ObjectWrap) return isCastableToNumeric(((ObjectWrap)o).getEmbededObject("notanumber"));
099    
100            else if(o instanceof Castable) {
101                    return Decision.isValid(((Castable)o).castToDoubleValue(Double.NaN));
102                    
103            }
104                    return false;
105            }
106            
107            public static boolean isCastableToDate(Object o) {
108                    if(isDateAdvanced(o, true)) return true;
109                    else if(isBoolean(o)) return true;
110            
111            else if(o instanceof ObjectWrap) return isCastableToDate(((ObjectWrap)o).getEmbededObject("notadate"));
112    
113            else if(o instanceof Castable) {
114                    return ((Castable)o).castToDateTime(null)!=null;
115                    
116            }
117                    return false;
118            }
119    
120            /**
121             * tests if value is Numeric
122             * @param value value to test
123             * @return is value numeric
124             */
125            public static boolean isNumeric(Object value, boolean alsoBooleans) {
126                    if(alsoBooleans && isBoolean(value)) return true;
127                    return isNumeric(value);
128            }
129            
130            /**
131             * tests if String value is Numeric
132             * @param str value to test
133             * @return is value numeric
134             */
135            public static boolean isNumeric(String str) {
136            if(str==null) return false; 
137            str=str.trim();
138            
139            int pos=0; 
140            int len=str.length(); 
141            if(len==0) return false; 
142            char curr=str.charAt(pos); 
143            
144            if(curr=='+' || curr=='-') { 
145                    if(len==++pos) return false; 
146                    curr=str.charAt(pos); 
147            }
148            
149            boolean hasDot=false; 
150            boolean hasExp=false; 
151            for(;pos<len;pos++) { 
152                curr=str.charAt(pos); 
153                if(curr<'0') {
154                    if(curr=='.') { 
155                        if(pos+1>=len || hasDot) return false; 
156                        hasDot=true; 
157                    } 
158                    else return false;
159                }
160                else if(curr>'9') {
161                    if(curr=='e' || curr=='E') { 
162                        if(pos+1>=len || hasExp) return false; 
163                        hasExp=true; 
164                        hasDot=true; 
165                    }
166                    else return false;
167                }
168            } 
169            if(hasExp){
170                    try{
171                            Double.parseDouble(str);
172                            return true;
173                    }
174                    catch( NumberFormatException e){
175                            return false;
176                    } 
177            }
178            return true; 
179        } 
180    
181    
182            public static boolean isInteger(Object value) {
183                    return isInteger(value,false);          
184            }
185    
186            public static boolean isInteger(Object value,boolean alsoBooleans) {
187                    if(!alsoBooleans && value instanceof Boolean) return false;
188                    double dbl = Caster.toDoubleValue(value,Double.NaN);
189                    if(!Decision.isValid(dbl)) return false;
190                    int i=(int)dbl;
191                    return i==dbl;          
192            }
193    
194             /** tests if String value is Hex Value
195             * @param str value to test
196             * @return is value numeric
197             */
198            public static boolean isHex(String str) { 
199          if(str==null || str.length()==0) return false; 
200          
201          for(int i=str.length()-1;i>=0;i--) {
202              char c=str.charAt(i);
203              if(!(c>='0' && c<='9')) {
204                  c=Character.toLowerCase(c);
205                  if(!(c=='a' || c=='b' || c=='c' || c=='d' || c=='e' || c=='f'))return false;
206              }
207          }
208          return true;
209            }
210    
211            /** tests if String value is UUID Value
212             * @param str value to test
213             * @return is value numeric
214             * @deprecated use instead <code>isUUId(Object obj)</code>
215             */
216            public static boolean isUUID(Object obj) { 
217                    return isUUId(obj);
218            }
219            
220             /** tests if String value is UUID Value
221             * @param str value to test
222             * @return is value numeric
223             */
224            public static boolean isUUId(Object obj) { 
225                    String str=Caster.toString(obj,null);
226                    if(str==null) return false;
227    
228                    if(str.length()==35) {      
229                    return 
230                    Decision.isHex(str.substring(0,8)) &&
231                    str.charAt(8)=='-' &&
232                    Decision.isHex(str.substring(9,13)) &&
233                    str.charAt(13)=='-' &&
234                    Decision.isHex(str.substring(14,18)) &&
235                    str.charAt(18)=='-' &&
236                    Decision.isHex(str.substring(19));
237                }
238                    return false;
239            }
240            
241    
242            /**
243             * @param obj
244             * @return
245             * @deprecated use instead <code>isGUId(Object)</code>
246             */
247            public static boolean isGUID(Object obj) { 
248                    return isGUId(obj);
249            }
250    
251            public static boolean isGUId(Object obj) { 
252                    String str=Caster.toString(obj,null);
253                    if(str==null) return false;
254    
255            
256                    // GUID
257                if(str.length()==36) {          
258                    return 
259                    Decision.isHex(str.substring(0,8)) &&
260                    str.charAt(8)=='-' &&
261                    Decision.isHex(str.substring(9,13)) &&
262                    str.charAt(13)=='-' &&
263                    Decision.isHex(str.substring(14,18)) &&
264                    str.charAt(18)=='-' &&
265                    Decision.isHex(str.substring(19,23)) &&
266                    str.charAt(23)=='-' &&
267                    Decision.isHex(str.substring(24));
268                }
269                return false;
270            }
271            
272    
273            public static boolean isGUIdSimple(Object obj) { 
274                    String str=Caster.toString(obj,null);
275                    if(str==null) return false;
276    
277            
278                    // GUID
279                if(str.length()==36) {          
280                    return 
281                    str.charAt(8)=='-' &&
282                    str.charAt(13)=='-' &&
283                    str.charAt(18)=='-' &&
284                    str.charAt(23)=='-';
285                }
286                return false;
287            }
288    
289            /**
290             * tests if value is a Boolean (Numbers are not acctepeted)
291             * @param value value to test
292             * @return is value boolean
293             */
294            public static boolean isBoolean(Object value) {
295            if(value instanceof Boolean) return true;
296            else if(value instanceof String) {
297                            return isBoolean(value.toString());
298                    }
299            else if(value instanceof ObjectWrap) return isBoolean(((ObjectWrap)value).getEmbededObject(null));
300                    else return false;
301            }
302    
303            public static boolean isCastableToBoolean(Object value) {
304                    if(value instanceof Boolean) return true;
305                    if(value instanceof Number) return true;
306            else if(value instanceof String) {
307                    String str = (String)value;
308                            return isBoolean(str) || isNumeric(str);
309                    }
310            else if(value instanceof Castable) {
311                return ((Castable)value).castToBoolean(null)!=null;
312                
313            }
314            else if(value instanceof ObjectWrap) return isCastableToBoolean(((ObjectWrap)value).getEmbededObject(null));
315                    else return false;
316            }
317            
318            public static boolean isBoolean(Object value, boolean alsoNumbers) {
319                    if(isBoolean(value)) return true;
320            else if(alsoNumbers) return isNumeric(value);
321            else return false;
322            }
323    
324        /**
325         * tests if value is a Boolean
326         * @param str value to test
327         * @return is value boolean
328         */
329        public static boolean isBoolean(String str) {
330            //str=str.trim();
331            if(str.length()<2) return false;
332            
333            switch(str.charAt(0)) {
334                case 't':
335                case 'T': return str.equalsIgnoreCase("true");
336                case 'f':
337                case 'F': return str.equalsIgnoreCase("false");
338                case 'y':
339                case 'Y': return str.equalsIgnoreCase("yes");
340                case 'n':
341                case 'N': return str.equalsIgnoreCase("no");
342            }
343            return false;
344        }   
345    
346            /**
347             * tests if value is DateTime Object
348             * @param value value to test
349             * @param alsoNumbers interpret also a number as date
350             * @return is value a DateTime Object
351             */
352        public static boolean isDate(Object value,boolean alsoNumbers) {
353            return isDateSimple(value, alsoNumbers);
354        }
355    
356            public static boolean isDateSimple(Object value,boolean alsoNumbers) {
357                    
358            //return DateCaster.toDateEL(value)!=null;
359                    if(value instanceof DateTime)           return true;
360                    else if(value instanceof Date)          return true;
361                    // wrong timezone but this isent importend because date will not be importend
362                    else if(value instanceof String)        return DateCaster.toDateSimple(value.toString(),alsoNumbers,TimeZone.getDefault(),null)!=null;
363                    else if(value instanceof ObjectWrap) {
364                    return isDateSimple(((ObjectWrap)value).getEmbededObject(null),alsoNumbers);
365            }
366            else if(value instanceof Castable)      {
367                        return ((Castable)value).castToDateTime(null)!=null;
368                
369                    }
370                    else if(alsoNumbers && value instanceof Number) return true;
371                    else if(value instanceof Calendar) return true;
372                    return false;
373            }
374            
375            public static boolean isDateAdvanced(Object value,boolean alsoNumbers) {
376                //return DateCaster.toDateEL(value)!=null;
377                    if(value instanceof DateTime)           return true;
378                    else if(value instanceof Date)          return true;
379                    // wrong timezone but this isent importend because date will not be importend
380                    else if(value instanceof String)        return DateCaster.toDateAdvanced(value.toString(),alsoNumbers,TimeZone.getDefault(),null)!=null;
381                    else if(value instanceof Castable)      {
382                        return ((Castable)value).castToDateTime(null)!=null;
383                 
384                    }
385                    else if(alsoNumbers && value instanceof Number) return true;
386                    else if(value instanceof ObjectWrap) {
387                    return isDateAdvanced(((ObjectWrap)value).getEmbededObject(null),alsoNumbers);
388            }
389            else if(value instanceof Calendar) return true;
390                    return false;
391            }
392            
393            private static char[] DATE_DEL=new char[]{'.','/','-'};
394            
395            public static boolean isUSDate(Object value) {
396                    String str = Caster.toString(value,"");
397                    return isUSorEuroDateEuro(str,false);
398            }
399            
400            public static boolean isUSDate(String str) {
401                    return isUSorEuroDateEuro(str,false);
402            }
403            
404            public static boolean isEuroDate(Object value) {
405                    String str = Caster.toString(value,"");
406                    return isUSorEuroDateEuro(str,true);
407            }
408            
409            public static boolean isEuroDate(String str) {
410                    return isUSorEuroDateEuro(str,true);
411            }
412            
413            private static boolean isUSorEuroDateEuro(String str, boolean isEuro) {
414                    if(StringUtil.isEmpty(str)) return false;
415                    
416                    for(int i=0;i<DATE_DEL.length;i++) {
417                            Array arr = railo.runtime.type.List.listToArrayRemoveEmpty(str,DATE_DEL[i]);
418                            if(arr.size()!=3) continue;
419    
420                            int month=Caster.toIntValue(    arr.get(isEuro?2:1,Constants.INTEGER_0),Integer.MIN_VALUE);
421                            int day=Caster.toIntValue(              arr.get(isEuro?1:2,Constants.INTEGER_0),Integer.MIN_VALUE);
422                            int year=Caster.toIntValue(             arr.get(3,Constants.INTEGER_0),Integer.MIN_VALUE);
423    
424                            
425                            if(month==Integer.MIN_VALUE) continue;
426                            if(month>12) continue;
427                            if(day==Integer.MIN_VALUE) continue;
428                            if(day>31) continue;
429                            if(year==Integer.MIN_VALUE) continue;
430                            if(DateTimeUtil.getInstance().toTime(null,year, month, day, 0, 0, 0,0, Long.MIN_VALUE)==Long.MIN_VALUE) continue;
431                            return true;
432                    }
433                    return false;
434            }
435            
436            public static boolean isCastableToStruct(Object o) {
437                    if(isStruct(o)) return true;
438                    if(o == null) return false;
439                    else if(o instanceof ObjectWrap) {
440                    if(o instanceof JavaObject ) return true;
441                return isCastableToStruct(((ObjectWrap)o).getEmbededObject(null));
442            }
443                    if(Decision.isSimpleValue(o)){
444                            return false;
445                    }
446                    //if(isArray(o) || isQuery(o)) return false;
447            return false;
448            }
449    
450            /**
451             * tests if object is a struct 
452             * @param o
453             * @return is struct or not
454             */
455            public static boolean isStruct(Object o) {
456                    if(o instanceof Struct) return true;
457            else if(o instanceof Map)return true;
458            else if(o instanceof Node)return true;
459                    return false;
460            }
461    
462            
463            /**
464             * can this type be casted to a array
465             * @param o
466             * @return
467             * @throws PageException
468             */
469            public static boolean isCastableToArray(Object o) {
470            if(isArray(o)) return true;
471            //else if(o instanceof XMLStruct) return true;
472            else if(o instanceof Struct) {
473                Struct sct=(Struct) o;
474                Collection.Key[] keys=sct.keys();
475                try {
476                    for(int i=0;i<keys.length;i++) Caster.toIntValue(keys[i].toString());
477                    return true;
478                } 
479                catch (Exception e) {
480                    return false;
481                }
482            }
483            return false;
484        }
485            
486            /**
487             * tests if object is a array 
488             * @param o
489             * @return is array or not
490             */
491            public static boolean isArray(Object o) {
492                    if(o instanceof Array)                          return true;
493                    if(o instanceof List)                           return true;
494                    if(isNativeArray(o))                            return true;
495                    if(o instanceof ObjectWrap) {
496                return isArray(((ObjectWrap)o).getEmbededObject(null));
497            }
498            return false;
499            }
500    
501            /**
502             * tests if object is a native java array 
503             * @param o
504             * @return is a native (java) array
505             */
506            public static boolean isNativeArray(Object o) {
507                    //return o.getClass().isArray();
508                    if(o instanceof Object[])                       return true;
509                    else if(o instanceof boolean[])         return true;
510                    else if(o instanceof byte[])            return true;
511                    else if(o instanceof char[])            return true;
512                    else if(o instanceof short[])           return true;
513                    else if(o instanceof int[])                     return true;
514                    else if(o instanceof long[])            return true;
515                    else if(o instanceof float[])           return true;
516                    else if(o instanceof double[])          return true;
517                    return false;
518            }
519    
520            /**
521             * tests if object is catable to a binary  
522             * @param object
523             * @return boolean
524             */
525            public static boolean isCastableToBinary(Object object,boolean checkBase64String) {
526                    if(isBinary(object))return true;
527                    if(object instanceof InputStream) return true;
528                    if(object instanceof ByteArrayOutputStream) return true;
529                    if(object instanceof Blob) return true;
530            
531                    // Base64 String
532                    if(!checkBase64String) return false;
533                    String str = Caster.toString(object,null);
534            if(str==null) return false;
535            return Base64Util.isBase64(str);
536                    
537            }
538    
539            /**
540             * tests if object is a binary  
541             * @param object
542             * @return boolean
543             */
544            public static boolean isBinary(Object object) {
545                    if(object instanceof byte[]) return true;
546                    if(object instanceof ObjectWrap) return isBinary(((ObjectWrap)object).getEmbededObject(""));
547                    return false;
548            }
549    
550            /**
551             * tests if object is a Component  
552             * @param object
553             * @return boolean
554             */
555            public static boolean isComponent(Object object) {
556                    return object instanceof Component;
557            }
558    
559            /**
560             * tests if object is a Query  
561             * @param object
562             * @return boolean
563             */
564            public static boolean isQuery(Object object) {
565                    if(object instanceof Query)return true;
566                    else if(object instanceof ObjectWrap) {
567                return isQuery(((ObjectWrap)object).getEmbededObject(null));
568            }
569            return false;
570            }
571    
572            /**
573             * tests if object is a binary  
574             * @param object
575             * @return boolean
576             */
577            public static boolean isUserDefinedFunction(Object object) {
578                    return object instanceof UDF;
579            }
580            
581            /**
582             * tests if year is a leap year 
583             * @param year year to check
584             * @return boolean
585             */
586            public static final boolean isLeapYear(int year) {
587                    return DateTimeUtil.getInstance().isLeapYear(year);
588                    //return new GregorianCalendar().isLeapYear(year);
589        }
590            
591            /**
592             * tests if object is a WDDX Object 
593             * @param o Object to check
594             * @return boolean
595             */
596            public static boolean isWddx(Object o) {
597                    if(!(o instanceof String)) return false;
598                    String str=o.toString();
599                    if(!(str.indexOf("wddxPacket")>0)) return false;
600                    
601                    // wrong timezone but this isent importend because date will not be used
602                    WDDXConverter converter =new WDDXConverter(TimeZone.getDefault(),false,true);
603                    try {
604                            converter.deserialize(Caster.toString(o),true);
605                    } 
606                    catch (Exception e) {
607                            return false;
608                    }
609                    return true;
610            }
611            
612            /**
613             * tests if object is a XML Object 
614             * @param o Object to check
615             * @return boolean
616             */
617            public static boolean isXML(Object o) {
618                    if(o instanceof Node || o instanceof NodeList) return true;
619                    if(o instanceof ObjectWrap) {
620                return isXML(((ObjectWrap)o).getEmbededObject(null));
621            }
622            try {
623                XMLCaster.toXMLStruct(XMLUtil.parse(XMLUtil.toInputSource(null, o),null,false),false);
624                return true;
625            }
626            catch(Exception outer) {
627                return false;
628            }
629                    
630            }
631            
632            public static boolean isVoid(Object o) {
633                    if(o==null)return true;
634            else if(o instanceof String)    return o.toString().length()==0;
635            else if(o instanceof Number)    return ((Number)o).intValue()==0;
636            else if(o instanceof Boolean)   return ((Boolean)o).booleanValue()==false ;
637            else if(o instanceof ObjectWrap)return isVoid(((ObjectWrap)o).getEmbededObject(("isnotnull")));
638                    return false;
639            }
640            
641            
642            /**
643             * tests if object is a XML Element Object 
644             * @param o Object to check
645             * @return boolean
646             */
647            public static boolean isXMLElement(Object o) {
648                    return o instanceof Element;
649            }
650            
651            /**
652             * tests if object is a XML Document Object 
653             * @param o Object to check
654             * @return boolean
655             */
656            public static boolean isXMLDocument(Object o) {
657                    return o instanceof Document;
658            }
659            
660            /**
661             * tests if object is a XML Root Element Object 
662             * @param o Object to check
663             * @return boolean
664             */
665            public static boolean isXMLRootElement(Object o) {
666                    if(o instanceof Node) {
667                            Node n=(Node)o;
668                            if(n instanceof XMLStruct)n=((XMLStruct)n).toNode();
669                            return n.getOwnerDocument()!=null && n.getOwnerDocument().getDocumentElement()==n;
670                    }
671                    return false;
672            }
673    
674            /**
675             * @param string
676             * @return returns if string represent a variable name
677             */
678            public static boolean isVariableName(Object obj) {
679                    if(obj instanceof String) return isVariableName((String)obj);
680                    return false;
681            }
682    
683            /**
684             * @param string
685             * @return returns if string represent a variable name
686             */
687            public static boolean isVariableName(String string) {
688                    if(string.length()==0)return false;
689                    int len=string.length();
690                    int pos=0;
691                    while(pos<len) {
692                        char first=string.charAt(pos);
693                        if(!((first>='a' && first<='z')||(first>='A' && first<='Z')||(first=='_')))
694                                    return false;
695                        pos++;
696                        for(;pos<len;pos++) {
697                                    char c=string.charAt(pos);
698                                    if(!((c>='a' && c<='z')||(c>='A' && c<='Z')||(c>='0' && c<='9')||(c=='_')))
699                                            break;
700                            }
701                        if(pos==len) return true;
702                        if(string.charAt(pos)=='.')pos++;
703                    }
704                    return false;
705            }
706            
707            /**
708             * @param string
709             * @return returns if string represent a variable name
710             */
711            public static boolean isSimpleVariableName(String string) {
712                    if(string.length()==0)return false;
713                    
714                    char first=string.charAt(0);
715                    if(!((first>='a' && first<='z')||(first>='A' && first<='Z')||(first=='_')))
716                            return false;
717                    for(int i=string.length()-1;i>0;i--) {
718                            char c=string.charAt(i);
719                            if(!((c>='a' && c<='z')||(c>='A' && c<='Z')||(c>='0' && c<='9')||(c=='_')))
720                                    return false;
721                    }       
722                    return true;
723            }
724            
725            /**
726             * @param string
727             * @return returns if string represent a variable name
728             */
729            public static boolean isSimpleVariableName(Collection.Key key) {
730                    String strKey = key.getLowerString();
731                    if(strKey.length()==0)return false;
732                    
733                    char first=strKey.charAt(0);
734                    if(!((first>='a' && first<='z')||(first=='_')))
735                            return false;
736                    for(int i=strKey.length()-1;i>0;i--) {
737                            char c=strKey.charAt(i);
738                            if(!((c>='a' && c<='z')||(c>='0' && c<='9')||(c=='_')))
739                                    return false;
740                    }       
741                    return true;
742            }
743    
744            /**
745             * returns if object is a cold fusion object
746             * @param o Object to check
747             * @return is or not
748             */
749            public static boolean isObject(Object o) {
750                    return isComponent(o)
751                    
752                            || (!isArray(o)
753                            && !isQuery(o)
754                            && !isSimpleValue(o)
755                            && !isStruct(o)
756                            && !isUserDefinedFunction(o)
757                            && !isXML(o));
758            }
759    
760        /**
761         * @param obj
762         * @return return if a String is "Empty", that means NULL or String with length 0 (whitespaces will not counted) 
763         */
764        public static boolean isEmpty(Object obj) {
765            if(obj instanceof String)return StringUtil.isEmpty((String)obj);
766            return obj==null;
767        }
768    
769    
770        /**
771         * @deprecated use instead <code>StringUtil.isEmpty(String)</code>
772         * @param str
773         * @return return if a String is "Empty", that means NULL or String with length 0 (whitespaces will not counted) 
774         */
775        public static boolean isEmpty(String str) {
776            return StringUtil.isEmpty(str);
777        }
778        
779        /**
780         * @deprecated use instead <code>StringUtil.isEmpty(String)</code>
781         * @param str
782         * @param trim 
783         * @return return if a String is "Empty", that means NULL or String with length 0 (whitespaces will not counted) 
784         */
785        public static boolean isEmpty(String str, boolean trim) {
786            return StringUtil.isEmpty(str,trim);
787        }
788        
789    
790            /**
791             * returns if a value is a credit card
792             * @param value
793             * @return is credit card
794             */
795            public static boolean isCreditCard(Object value) {
796                    return ValidateCreditCard.isValid(Caster.toString(value,"0"));
797            }
798            
799    
800            /**
801             * returns if given object is a email
802             * @param value
803             * @return
804             */
805            public static boolean isEmail(Object value) {
806                    String str = Caster.toString(value,null);
807                    if(str==null)return false;
808                    
809                    if(emailPattern==null) {
810                            String prefix="\\%\\+a-zA-Z_0-9-'~";
811                            emailPattern=Pattern.compile("^["+prefix+"]+(\\.["+prefix+"]+)*@([a-zA-Z_0-9-]+\\.)+[a-zA-Z]{2,7}$");
812                    }       
813                    return emailPattern.matcher(str).matches();
814            }       
815            
816            
817            
818            /**
819             * returns if given object is a social security number (usa)
820             * @param value
821             * @return
822             */
823            public static boolean isSSN(Object value) {
824                    String str = Caster.toString(value,null);
825                    if(str==null)return false;
826                    
827                    if(ssnPattern==null)
828                            ssnPattern=Pattern.compile("^[0-9]{3}[-|]{1}[0-9]{2}[-|]{1}[0-9]{4}$");
829                    
830                    return ssnPattern.matcher(str.trim()).matches();
831                    
832            }
833            
834            /**
835             * returns if given object is a phone
836             * @param value
837             * @return
838             */
839            public static boolean isPhone(Object value) {
840                    String str = Caster.toString(value,null);
841                    if(str==null)return false;
842                    
843                    if(phonePattern==null)
844                            phonePattern=Pattern.compile("^(\\+?1?[ \\-\\.]?([\\(]?([1-9][0-9]{2})[\\)]?))?[ ,\\-,\\.]?([^0-1]){1}([0-9]){2}[ ,\\-,\\.]?([0-9]){4}(( )((x){0,1}([0-9]){1,5}){0,1})?$");
845                    return phonePattern.matcher(str.trim()).matches();
846                    
847            }       
848    
849            /**
850             * returns if given object is a URL
851             * @param value
852             * @return
853             */
854            public static boolean isURL(Object value) {
855                    String str = Caster.toString(value,null);
856                    if(str==null)return false;
857                    
858                    if(urlPattern==null)
859                            urlPattern=Pattern.compile("^((http|https|ftp|file)\\:\\/\\/([a-zA-Z0-0]*:[a-zA-Z0-0]*(@))?[a-zA-Z0-9-\\.]+(\\.[a-zA-Z]{2,3})?(:[a-zA-Z0-9]*)?\\/?([a-zA-Z0-9-\\._\\? \\,\\'\\/\\+&amp;%\\$#\\=~])*)|((mailto)\\:[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*@([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9]{2,7})|((news)\\: [a-zA-Z0-9\\.]*)$");
860                    return urlPattern.matcher(str.trim()).matches();
861            }
862            
863            /**
864             * returns if given object is a zip code
865             * @param value
866             * @return
867             */
868            public static boolean isZipCode(Object value) {
869                    String str = Caster.toString(value,null);
870                    if(str==null)return false;
871                    
872                    if(zipPattern==null)
873                            zipPattern=Pattern.compile("([0-9]{5,5})|([0-9]{5,5}[- ]{1}[0-9]{4,4})");
874                    return zipPattern.matcher(str.trim()).matches();
875            }
876    
877            public static boolean isString(Object o) {
878                    if(o instanceof String)                 return true;
879            else if(o instanceof Boolean)   return true;
880            else if(o instanceof Number)    return true;
881            else if(o instanceof Date)              return true;
882            else if(o instanceof Castable) {
883                return ((Castable)o).castToString(STRING_DEFAULT_VALUE)!=STRING_DEFAULT_VALUE;
884                
885            }
886            else if(o instanceof Clob)              return true;
887            else if(o instanceof Node)              return true;
888            else if(o instanceof Map || o instanceof List || o instanceof Function) return false;
889            else if(o == null) return true;
890            else if(o instanceof ObjectWrap) return isString(((ObjectWrap)o).getEmbededObject(""));
891                    return true;
892            }
893            public static boolean isCastableToString(Object o) {
894                    return isString(o);
895            }
896            
897        
898        public static boolean isValid(String type, Object value) throws ExpressionException {
899            type=StringUtil.toLowerCase(type.trim());
900            char first = type.charAt(0);
901            switch(first) {
902            case 'a':
903                    if("any".equals(type))                  return true;//isSimpleValue(value);
904                    if("array".equals(type))                return isArray(value);
905            break;
906            case 'b':
907                    if("binary".equals(type))               return isBinary(value);
908                    if("boolean".equals(type))              return isBoolean(value,true);
909            break;
910            case 'c':
911                    if("creditcard".equals(type))   return isCreditCard(value);
912                    if("component".equals(type))    return isComponent(value);
913                    if("cfc".equals(type))                  return isComponent(value);
914            break;
915            case 'd':
916                    if("date".equals(type))                 return isDateAdvanced(value,true);  // ist zwar nicht logisch aber ident. zu Neo
917                    if("double".equals(type))               return isCastableToNumeric(value);
918            break;
919            case 'e':
920                    if("eurodate".equals(type))             return isEuroDate(value); 
921                    if("email".equals(type))                return isEmail(value);
922            break;
923            case 'f':
924                    if("float".equals(type))                return isNumeric(value,true);
925            break;
926            case 'g':
927                    if("guid".equals(type))                 return isGUId(value);
928            break;
929            case 'i':
930                    if("integer".equals(type))              return isInteger(value,false);
931            break;
932            case 'n':
933                    if("numeric".equals(type))              return isCastableToNumeric(value);
934                    if("number".equals(type))               return isCastableToNumeric(value);
935                    if("node".equals(type))                 return isXML(value); 
936            break;
937            case 'p':
938                    if("phone".equals(type))                return isPhone(value);
939            break;
940            case 'q':
941                    if("query".equals(type))                return isQuery(value);
942            break;
943            case 's':
944                    if("simple".equals(type))               return isSimpleValue(value);    
945                    if("struct".equals(type))               return isStruct(value);
946                    if("ssn".equals(type))                  return isSSN(value);
947                    if("social_security_number".equals(type))return isSSN(value);
948                    if("string".equals(type))               return isString(value);
949            break;
950            case 't':
951                    if("telephone".equals(type))    return isPhone(value);
952                    if("time".equals(type))                 return isDateAdvanced(value,false);
953            break;
954            case 'u':
955                    if("usdate".equals(type))               return isUSDate(value); 
956                    if("uuid".equals(type))                 return isUUId(value);
957                    if("url".equals(type))                  return isURL(value);
958            break;
959            case 'v':
960                    if("variablename".equals(type)) return isVariableName(Caster.toString(value,""));
961            break;
962            case 'x':
963                    if("xml".equals(type))  return isXML(value); // DIFF 23
964            break;
965            case 'z':
966                    if("zip".equals(type))                  return isZipCode(value);
967                    if("zipcode".equals(type))              return isZipCode(value);
968            break;
969            }
970            throw new ExpressionException("invalid type ["+type+"], valid types are [any,array,binary,boolean,component,creditcard,date,time,email,eurodate,float,numeric,guid,integer,query,simple,ssn,string,struct,telephone,URL,UUID,USdate,variableName,zipcode]");
971                    
972        }
973        
974        
975        
976        
977        
978        
979        public static boolean isCastableTo(String type, Object o, boolean alsoPattern) {
980            
981            type=StringUtil.toLowerCase(type).trim();
982            if(type.length()>2) {
983                char first=type.charAt(0);
984                switch(first) {
985                    case 'a':
986                        if(type.equals("any")) {
987                            return true;
988                        }
989                        else if(type.equals("array")) {
990                            return isCastableToArray(o);
991                        }
992                        break;
993                    case 'b':
994                        if(type.equals("boolean") || type.equals("bool")) {
995                            return isCastableToBoolean(o);
996                        }
997                        else if(type.equals("binary")) {
998                            return isCastableToBinary(o,true);
999                        }
1000                        else if(type.equals("base64")) {
1001                            return Caster.toBase64(o,null,null)!=null;
1002                        }
1003                        break;
1004                    case 'c':
1005                        if(alsoPattern && type.equals("creditcard")) {
1006                            return Caster.toCreditCard(o,null)!=null;
1007                        }
1008                        break;
1009                    case 'd':
1010                            if(type.equals("date")) {
1011                            return isDateAdvanced(o, true);
1012                        }
1013                        else if(type.equals("datetime")) {
1014                            return isDateAdvanced(o, true);
1015                        }
1016                        else if(type.equals("double")) {
1017                            return isCastableToNumeric(o);
1018                        }
1019                        else if(type.equals("decimal")) {
1020                            return Caster.toDecimal(o,null)!=null;
1021                        }
1022                        break;
1023                    case 'e':
1024                        if(type.equals("eurodate")) {
1025                            return isDateAdvanced(o, true);
1026                        }
1027                        else if(alsoPattern && type.equals("email")) {
1028                            return Caster.toEmail(o,null)!= null;
1029                        }
1030                        break;
1031                    case 'f':
1032                        if(type.equals("float")) {
1033                            return isCastableToNumeric(o);
1034                        }
1035                        break;
1036                    case 'g':
1037                        if(type.equals("guid")) {
1038                            return isGUId(o);
1039                        }
1040                        break;
1041                    case 'i':
1042                        if(type.equals("integer") || type.equals("int")) {
1043                            return isCastableToNumeric(o);
1044                        }
1045                        break;
1046                    case 'l':
1047                        if(type.equals("long")) {
1048                            return isCastableToNumeric(o);
1049                        }
1050                        break;
1051                    case 'n':
1052                        if(type.equals("numeric")) {
1053                            return isCastableToNumeric(o);
1054                        }
1055                        else if(type.equals("number")) {
1056                            return isCastableToNumeric(o);
1057                        }
1058                        break;
1059                    case 'o':
1060                        if(type.equals("object")) {
1061                            return true;
1062                        }
1063                        else if(type.equals("other")) {
1064                            return true;
1065                        }
1066                        break;
1067                    case 'p':
1068                        if(alsoPattern && type.equals("phone")) {
1069                            return Caster.toPhone(o,null)!=null;
1070                        }
1071                        break;
1072                    case 'q':
1073                        if(type.equals("query")) {
1074                            return isQuery(o);
1075                        }
1076                        break;
1077                    case 's':
1078                        if(type.equals("string")) {
1079                            return isCastableToString(o);
1080                        }
1081                        else if(type.equals("struct")) {
1082                            return isCastableToStruct(o);
1083                        }
1084                        else if(type.equals("short")) {
1085                            return isCastableToNumeric(o);
1086                        }
1087                        else if(alsoPattern && (type.equals("ssn") ||type.equals("social_security_number"))) {
1088                            return Caster.toSSN(o,null)!=null;
1089                        }
1090                        break;
1091                    case 't':
1092                        if(type.equals("timespan")) {
1093                            return Caster.toTimespan(o,null)!=null;
1094                        }
1095                        if(type.equals("time")) {
1096                            return isDateAdvanced(o, true);
1097                        }
1098                        if(alsoPattern && type.equals("telephone")) {
1099                            return Caster.toPhone(o,null)!=null;
1100                        }
1101                    case 'u':
1102                        if(type.equals("uuid")) {
1103                            return isUUId(o);
1104                        }
1105                        if(type.equals("usdate")) {
1106                            return isDateAdvanced(o, true);
1107                            //return DateCaster.toDate(o,pc.getTimeZone());
1108                        }
1109                        if(alsoPattern && type.equals("url")) {
1110                            return Caster.toURL(o,null)!=null;
1111                        }
1112                        break;
1113                    case 'v':
1114                        if(type.equals("variablename")) {
1115                            return isVariableName(o);
1116                        }
1117                        else if(type.equals("void")) {
1118                            return isVoid(o);//Caster.toVoid(o,Boolean.TRUE)!=Boolean.TRUE;
1119                        }
1120                        else if(type.equals("variable_name")) {
1121                            return isVariableName(o);
1122                        }
1123                        else if(type.equals("variable-name")) {
1124                            return isVariableName(o);
1125                        }
1126                        break;
1127                    case 'x':
1128                        if(type.equals("xml")) {
1129                            return isXML(o);
1130                        }
1131                        break;
1132                    case 'z':
1133                        if(alsoPattern && (type.equals("zip") || type.equals("zipcode"))) {
1134                            return Caster.toZip(o,null)!=null;
1135                        }
1136                    break;
1137               }
1138            }
1139            if(o instanceof Component) {
1140                Component comp=((Component)o);
1141                return comp.instanceOf(type);
1142            }
1143            if(isArrayType(type) && isArray(o)){
1144                    String t=type.substring(0,type.length()-2);
1145                    Array arr = Caster.toArray(o,null);
1146                    if(arr!=null){
1147                            Iterator it = arr.valueIterator();
1148                            while(it.hasNext()){
1149                                    if(!isCastableTo(t, it.next(), alsoPattern))
1150                                            return false;
1151                                    
1152                            }
1153                            return true;
1154                    }
1155                    
1156            }
1157                    return false;
1158        }
1159        
1160        
1161    
1162            private static boolean isArrayType(String type) {
1163                    return type.endsWith("[]");
1164            }
1165    
1166            public static boolean isCastableTo(short type,String strType, Object o) {
1167                    switch(type){
1168                    case CFTypes.TYPE_ANY:          return true;
1169                    case CFTypes.TYPE_STRING:               return isCastableToString(o);
1170            case CFTypes.TYPE_BOOLEAN:      return isCastableToBoolean(o);
1171            case CFTypes.TYPE_NUMERIC:      return isCastableToNumeric(o);
1172            case CFTypes.TYPE_STRUCT:       return isCastableToStruct(o);
1173            case CFTypes.TYPE_ARRAY:        return isCastableToArray(o);
1174            case CFTypes.TYPE_QUERY:        return isQuery(o);
1175            case CFTypes.TYPE_DATETIME:     return isDateAdvanced(o, true);
1176            case CFTypes.TYPE_VOID:         return isVoid(o);//Caster.toVoid(o,Boolean.TRUE)!=Boolean.TRUE;
1177            case CFTypes.TYPE_BINARY:       return isCastableToBinary(o,true);
1178            case CFTypes.TYPE_TIMESPAN:     return Caster.toTimespan(o,null)!=null;
1179            case CFTypes.TYPE_UUID:         return isUUId(o);
1180            case CFTypes.TYPE_GUID:         return isGUId(o);
1181            case CFTypes.TYPE_VARIABLE_NAME:return isVariableName(o);
1182            case CFTypes.TYPE_XML:          return isXML(o);
1183                    }
1184                    
1185            if(o instanceof Component) {
1186                    Component comp=((Component)o);
1187                return comp.instanceOf(strType);
1188            }
1189            if(isArrayType(strType) && isArray(o)){
1190                    String t=strType.substring(0,strType.length()-2);
1191                    Array arr = Caster.toArray(o,null);
1192                    if(arr!=null){
1193                            Iterator it = arr.valueIterator();
1194                            while(it.hasNext()){
1195                                    if(!isCastableTo(type,t, it.next()))
1196                                            return false;
1197                                    
1198                            }
1199                            return true;
1200                    }
1201                    
1202            }
1203            
1204                    return false;
1205            }
1206    
1207        public synchronized static boolean isDate(String str,Locale locale, TimeZone tz,boolean lenient) {
1208            str=str.trim();
1209            tz=ThreadLocalPageContext.getTimeZone(tz);
1210            DateFormat[] df;
1211    
1212            // get Calendar
1213            Calendar c=JREDateTimeUtil.getCalendar(locale);
1214            //synchronized(c){
1215                    // datetime
1216                    df=FormatUtil.getDateTimeFormats(locale,tz,false);//dfc[FORMATS_DATE_TIME];
1217                    for(int i=0;i<df.length;i++) {
1218                        try {
1219                            synchronized(c) {
1220                                    df[i].parse(str);
1221                                    return true;
1222                            }
1223                        }
1224                        catch (ParseException e) {}
1225                    }
1226                    // date
1227                    df=FormatUtil.getDateFormats(locale,tz,false);//dfc[FORMATS_DATE];
1228                    for(int i=0;i<df.length;i++) {
1229                        try {
1230                            df[i].setTimeZone(tz);
1231                            synchronized(c) {
1232                                    df[i].parse(str);
1233                                    return true;
1234                            }
1235                    }
1236                        catch (ParseException e) {}
1237                    }
1238                    
1239                    // time
1240                    df=FormatUtil.getTimeFormats(locale,tz,false);//dfc[FORMATS_TIME];
1241                    for(int i=0;i<df.length;i++) {
1242                        try {
1243                            df[i].setTimeZone(tz);
1244                            synchronized(c) {
1245                                    df[i].parse(str);
1246                                    return true;
1247                            }
1248                        } 
1249                        catch (ParseException e) {}
1250                    }
1251            //} 
1252            if(lenient) return isDateSimple(str, false);
1253            return false;
1254        }
1255    
1256            /**
1257             * Checks if number is valid (not infinity or NaN)
1258             * @param dbl
1259             * @return
1260             */
1261            public static boolean isValid(double dbl) {
1262                    return !Double.isNaN(dbl) && !Double.isInfinite(dbl);
1263            }
1264    }