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