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.IOException; 022import java.math.BigDecimal; 023import java.util.Calendar; 024import java.util.Date; 025import java.util.HashSet; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Locale; 029import java.util.Map; 030import java.util.Set; 031 032import lucee.commons.date.DateTimeUtil; 033import lucee.commons.lang.ExceptionUtil; 034import lucee.runtime.Component; 035import lucee.runtime.PageContext; 036import lucee.runtime.exp.ExpressionException; 037import lucee.runtime.exp.PageException; 038import lucee.runtime.i18n.LocaleFactory; 039import lucee.runtime.interpreter.VariableInterpreter; 040import lucee.runtime.op.date.DateCaster; 041import lucee.runtime.type.Collection; 042import lucee.runtime.type.Collection.Key; 043import lucee.runtime.type.UDFPlus; 044import lucee.runtime.type.dt.DateTime; 045import lucee.runtime.type.dt.DateTimeImpl; 046import lucee.runtime.type.ref.VariableReference; 047import lucee.runtime.type.wrap.ListAsArray; 048import lucee.runtime.type.wrap.MapAsStruct; 049 050/** 051 * class to compare objects and primitive value types 052 * 053 * 054 */ 055public final class Operator { 056 057 private static final Object NULL = new Object(); 058 059 060 /** 061 * compares two Objects 062 * @param left 063 * @param right 064 * @return different of objects as int 065 * @throws PageException 066 */ 067 public static int compare(Object left, Object right) throws PageException { 068 //print.dumpStack(); 069 if(left instanceof String) return compare((String)left,right); 070 else if(left instanceof Number) return compare(((Number)left).doubleValue(),right); 071 else if(left instanceof Boolean) return compare(((Boolean)left).booleanValue(),right); 072 else if(left instanceof Date) return compare((Date)left ,right); 073 else if(left instanceof Castable) return compare(((Castable)left) ,right); 074 else if(left instanceof Locale) return compare(((Locale)left) ,right); 075 else if(left==null) return compare("",right); 076 /*/NICE disabled at the moment left Comparable 077 else if(left instanceof Comparable) { 078 return ((Comparable)left).compareTo(right); 079 } */ 080 else if(left instanceof Character) return compare( ((Character)left).toString() , right ); 081 else if(left instanceof Calendar) return compare( ((Calendar)left).getTime() , right ); 082 else { 083 return error(false,true); 084 } 085 } 086 087 public static int compare(Locale left, Object right) throws PageException { 088 if(right instanceof String) return compare(left,(String)right); 089 else if(right instanceof Number) return compare(left,Caster.toString(right)); 090 else if(right instanceof Boolean) return compare(left,Caster.toString(right)); 091 else if(right instanceof Date) return compare(left,Caster.toString(right)); 092 else if(right instanceof Castable) return compare(left,((Castable)right).castToString()); 093 else if(right instanceof Locale) return left.toString().compareTo(right.toString()); 094 else if(right==null) return compare( left, "" ); 095 else if(right instanceof Character) return compare(left,((Character)right).toString()); 096 else if(right instanceof Calendar) return compare(left, Caster.toString(((Calendar)right).getTime()) ); 097 else return error(false,true); 098 } 099 100 public static int compare(Object left, Locale right) throws PageException { 101 return -compare(right,left); 102 } 103 104 public static int compare(Locale left, String right) { 105 Locale rightLocale = LocaleFactory.getLocale(right, null); 106 if(rightLocale==null) return LocaleFactory.toString(left).compareTo(right); 107 return left.toString().compareTo(rightLocale.toString()); 108 } 109 110 public static int compare(String left, Locale right) { 111 return -compare(right,left); 112 } 113 114 /** 115 * compares a Object with a String 116 * @param left 117 * @param right 118 * @return difference as int 119 * @throws PageException 120 */ 121 public static int compare(Object left, String right) throws PageException { 122 if(left instanceof String) return compare((String)left, right ); 123 else if(left instanceof Number) return compare( ((Number)left).doubleValue() , right ); 124 else if(left instanceof Boolean) return compare( ((Boolean)left).booleanValue(), right ); 125 else if(left instanceof Date) return compare( (Date)left , right ); 126 else if(left instanceof Castable) return ((Castable)left).compareTo(right ); 127 else if(left instanceof Locale) return compare( (Locale)left , right ); 128 else if(left==null) return "".compareToIgnoreCase(right); 129 else if(left instanceof Character) return compare( ((Character)left).toString() , right ); 130 else if(left instanceof Calendar) return compare( ((Calendar)left).getTime() , right ); 131 132 else return error(false,true); 133 } 134 135 /** 136 * compares a String with a Object 137 * @param left 138 * @param right 139 * @return difference as int 140 * @throws PageException 141 */ 142 public static int compare(String left, Object right) throws PageException { 143 if(right instanceof String) return compare(left,(String)right); 144 else if(right instanceof Number) return compare(left,((Number)right).doubleValue()); 145 else if(right instanceof Boolean) return compare(left,((Boolean)right).booleanValue()?1:0); 146 else if(right instanceof Date) return compare(left,(Date)right); 147 else if(right instanceof Castable) return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToString()); 148 else if(right instanceof Locale) return compare(left ,(Locale)right); 149 else if(right==null) return left.compareToIgnoreCase(""); 150 else if(right instanceof Character) return compare(left ,((Character)right).toString()); 151 else if(right instanceof Calendar) return compare(left, ((Calendar)right).getTime() ); 152 else return error(false,true); 153 } 154 155 /** 156 * compares a Object with a double 157 * @param left 158 * @param right 159 * @return difference as int 160 * @throws PageException 161 */ 162 public static int compare(Object left, double right) throws PageException { 163 if(left instanceof Number) return compare( ((Number)left).doubleValue() ,right ); 164 else if(left instanceof String) return compare( (String)left, right ); 165 else if(left instanceof Boolean) return compare( ((Boolean)left).booleanValue()?1D:0D , right ); 166 else if(left instanceof Date) return compare( ((Date)left) ,right); 167 else if(left instanceof Castable) return ((Castable)left).compareTo(right); 168 //else if(left instanceof Castable) return compare(((Castable)left).castToDoubleValue() , right ); 169 else if(left instanceof Locale) return compare( ((Locale)left), Caster.toString(right)); 170 else if(left==null) return -1; 171 else if(left instanceof Character) return compare(((Character)left).toString(),right); 172 else if(left instanceof Calendar) return compare( ((Calendar)left).getTime() , right ); 173 else { 174 return error(false,true); 175 } 176 } 177 178 /** 179 * compares a double with a Object 180 * @param left 181 * @param right 182 * @return difference as int 183 * @throws PageException 184 */ 185 public static int compare(double left, Object right) throws PageException { 186 if(right instanceof Number) return compare(left,((Number)right).doubleValue()); 187 else if(right instanceof String) return compare(left,(String)right); 188 else if(right instanceof Boolean) return compare(left,((Boolean)right).booleanValue()?1D:0D); 189 else if(right instanceof Date) return compare(left,((Date)right)); 190 else if(right instanceof Castable) return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToDoubleValue()); 191 else if(right instanceof Locale) return compare(Caster.toString(left) ,((Locale)right)); 192 else if(right==null) return 1; 193 else if(right instanceof Character) return compare(left ,((Character)right).toString()); 194 else if(right instanceof Calendar) return compare(left, ((Calendar)right).getTime() ); 195 else return error(true,false); 196 } 197 198 199 /** 200 * compares a Object with a boolean 201 * @param left 202 * @param right 203 * @return difference as int 204 * @throws PageException 205 */ 206 public static int compare(Object left, boolean right) throws PageException { 207 if(left instanceof Boolean) return compare(((Boolean)left).booleanValue(),right); 208 else if(left instanceof String) return compare((String)left,right); 209 else if(left instanceof Number) return compare(((Number)left).doubleValue(),right?1D:0D); 210 else if(left instanceof Date) return compare(((Date)left),right?1:0); 211 else if(left instanceof Castable) return ((Castable)left).compareTo(right ); 212 else if(left instanceof Locale) return compare(((Locale)left),Caster.toString(right)); 213 else if(left==null) return -1; 214 else if(left instanceof Character) return compare(((Character)left).toString(),right); 215 else if(left instanceof Calendar) return compare( ((Calendar)left).getTime() , right?1:0 ); 216 else return error(false,true); 217 } 218 219 /** 220 * compares a boolean with a Object 221 * @param left 222 * @param right 223 * @return difference as int 224 * @throws PageException 225 */ 226 public static int compare(boolean left, Object right) throws PageException { 227 if(right instanceof Boolean) return compare(left,((Boolean)right).booleanValue()); 228 else if(right instanceof String) return compare(left?1:0,(String)right); 229 else if(right instanceof Number) return compare(left?1D:0D,((Number)right).doubleValue()); 230 else if(right instanceof Date) return compare(left?1:0,((Date)right)); 231 else if(right instanceof Castable) return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToBooleanValue()); 232 else if(right instanceof Locale) return compare(Caster.toString(left),((Locale)right)); 233 else if(right==null) return 1; 234 else if(right instanceof Character) return compare(left ,((Character)right).toString()); 235 else if(right instanceof Calendar) return compare(left?1:0, ((Calendar)right).getTime() ); 236 else return error(true,false); 237 } 238 239 /** 240 * compares a Object with a Date 241 * @param left 242 * @param right 243 * @return difference as int 244 * @throws PageException 245 */ 246 public static int compare(Object left, Date right) throws PageException { 247 if(left instanceof String) return compare((String)left,right); 248 else if(left instanceof Number) return compare(((Number)left).doubleValue() ,right.getTime()/1000 ); 249 else if(left instanceof Boolean) return compare( ((Boolean)left).booleanValue()?1D:0D , right.getTime()/1000 ); 250 else if(left instanceof Date) return compare( ((Date)left) , right ); 251 else if(left instanceof Castable) return ((Castable)left).compareTo(Caster.toDatetime(right,null) ); 252 else if(left instanceof Locale) return compare( ((Locale)left) , Caster.toString(right)); 253 else if(left==null) return compare("", right); 254 else if(left instanceof Character) return compare(((Character)left).toString(),right); 255 else if(left instanceof Calendar) return compare( ((Calendar)left).getTime() , right ); 256 else return error(false,true); 257 } 258 259 /** 260 * compares a Date with a Object 261 * @param left 262 * @param right 263 * @return difference as int 264 * @throws PageException 265 */ 266 public static int compare(Date left, Object right) throws PageException { 267 if(right instanceof String) return compare(left,(String)right); 268 else if(right instanceof Number) return compare(left.getTime()/1000,((Number)right).doubleValue()); 269 else if(right instanceof Boolean) return compare(left.getTime()/1000,((Boolean)right).booleanValue()?1D:0D); 270 else if(right instanceof Date) return compare(left.getTime()/1000,((Date)right).getTime()/1000); 271 else if(right instanceof Castable) return -((Castable)right).compareTo(Caster.toDate(left,null));//compare(left ,(Date)((Castable)right).castToDateTime()); 272 else if(right instanceof Locale) return compare(Caster.toString(left),(Locale)right); 273 else if(right==null) return compare(left,""); 274 else if(right instanceof Character) return compare(left ,((Character)right).toString()); 275 else if(right instanceof Calendar) return compare(left.getTime()/1000, ((Calendar)right).getTime().getTime()/1000 ); 276 else return error(true,false); 277 } 278 279 public static int compare(Castable left, Object right) throws PageException { 280 if(right instanceof String) return left.compareTo((String)right); 281 else if(right instanceof Number) return left.compareTo(((Number)right).doubleValue()); 282 else if(right instanceof Boolean) return left.compareTo(((Boolean)right).booleanValue()?1d:0d); 283 else if(right instanceof Date) return left.compareTo(Caster.toDate(right,null)); 284 else if(right instanceof Castable) return compare(left.castToString() , ((Castable)right).castToString() ); 285 else if(right instanceof Locale) return compare(left.castToString() , (Locale)right); 286 else if(right == null) return compare(left.castToString(), "" ); 287 else if(right instanceof Character) return left.compareTo(((Character)right).toString()); 288 else if(right instanceof Calendar) return left.compareTo(new DateTimeImpl(((Calendar)right).getTime()) ); 289 else return error(true,false); 290 } 291 292 public static int compare(Object left, Castable right) throws PageException { 293 return -compare(right,left); 294 } 295 296 297 /** 298 * compares a String with a String 299 * @param left 300 * @param right 301 * @return difference as int 302 */ 303 public static int compare(String left, String right) { 304 if(Decision.isNumeric(left)) { 305 if(Decision.isNumeric(right)){ 306 // long numbers 307 if(left.length()>9 || right.length()>9) { 308 try{ 309 return new BigDecimal(left).compareTo(new BigDecimal(right)); 310 } 311 catch(Throwable t){ 312 ExceptionUtil.rethrowIfNecessary(t); 313 } 314 } 315 return compare(Caster.toDoubleValue(left,Double.NaN),Caster.toDoubleValue(right,Double.NaN)); 316 } 317 318 return compare(Caster.toDoubleValue(left,Double.NaN),right); 319 } 320 if(Decision.isBoolean(left)) 321 return compare(Caster.toBooleanValue(left,false)?1D:0D,right); 322// NICE Date compare, perhaps datetime to double 323 return left.compareToIgnoreCase(right); 324 } 325 326 /** 327 * compares a String with a double 328 * @param left 329 * @param right 330 * @return difference as int 331 */ 332 public static int compare(String left, double right) { 333 if(Decision.isNumeric(left)) { 334 if(left.length()>9) { 335 try{ 336 return new BigDecimal(left).compareTo(new BigDecimal(right)); 337 } 338 catch(Throwable t){ 339 ExceptionUtil.rethrowIfNecessary(t); 340 } 341 } 342 return compare(Caster.toDoubleValue(left,Double.NaN),right); 343 } 344 if(Decision.isBoolean(left)) 345 return compare(Caster.toBooleanValue(left,false),right); 346 347 if(left.length()==0) return -1; 348 char leftFirst=left.charAt(0); 349 if(leftFirst>='0' && leftFirst<='9') 350 return left.compareToIgnoreCase(Caster.toString(right)); 351 return leftFirst-'0'; 352 } 353 354 /** 355 * compares a String with a boolean 356 * @param left 357 * @param right 358 * @return difference as int 359 */ 360 public static int compare(String left, boolean right) { 361 if(Decision.isBoolean(left)) 362 return compare(Caster.toBooleanValue(left,false),right); 363 if(Decision.isNumeric(left)) 364 return compare(Caster.toDoubleValue(left,Double.NaN),right?1d:0d); 365 366 if(left.length()==0) return -1; 367 char leftFirst=left.charAt(0); 368 //print.ln(left+".compareTo("+Caster.toString(right)+")"); 369 //p(left); 370 if(leftFirst>='0' && leftFirst<='9') 371 return left.compareToIgnoreCase(Caster.toString(right?1D:0D)); 372 return leftFirst-'0'; 373 } 374 375 /** 376 * compares a String with a Date 377 * @param left 378 * @param right 379 * @return difference as int 380 * @throws PageException 381 */ 382 public static int compare(String left, Date right) throws PageException { 383 return -compare(right,left); 384 } 385 386 /** 387 * compares a double with a String 388 * @param left 389 * @param right 390 * @return difference as int 391 */ 392 public static int compare(double left, String right) { 393 return -compare(right,left); 394 } 395 396 /** 397 * compares a double with a double 398 * @param left 399 * @param right 400 * @return difference as int 401 */ 402 public static int compare(double left, double right) { 403 if((left)<(right))return -1; 404 else if((left)>(right))return 1; 405 else return 0; 406 } 407 408 /** 409 * compares a double with a boolean 410 * @param left 411 * @param right 412 * @return difference as int 413 */ 414 public static int compare(double left, boolean right) { 415 return compare(left,right?1d:0d); 416 } 417 418 /** 419 * compares a double with a Date 420 * @param left 421 * @param right 422 * @return difference as int 423 */ 424 public static int compare(double left, Date right) { 425 return compare(DateTimeUtil.getInstance().toDateTime(left).getTime()/1000,right.getTime()/1000); 426 } 427 428 /** 429 * compares a boolean with a double 430 * @param left 431 * @param right 432 * @return difference as int 433 */ 434 public static int compare(boolean left, double right) { 435 return compare(left?1d:0d, right); 436 } 437 438 /** 439 * compares a boolean with a double 440 * @param left 441 * @param right 442 * @return difference as int 443 */ 444 public static int compare(boolean left, String right) { 445 return -compare(right,left); 446 } 447 448 /** 449 * compares a boolean with a boolean 450 * @param left 451 * @param right 452 * @return difference as int 453 */ 454 public static int compare(boolean left, boolean right) { 455 if(left)return right?0:1; 456 return right?-1:0; 457 } 458 459 /** 460 * compares a boolean with a Date 461 * @param left 462 * @param right 463 * @return difference as int 464 */ 465 public static int compare(boolean left, Date right) { 466 return compare(left?1D:0D,right); 467 } 468 469 /** 470 * compares a Date with a String 471 * @param left 472 * @param right 473 * @return difference as int 474 * @throws PageException 475 */ 476 public static int compare(Date left, String right) throws PageException { 477 if(Decision.isNumeric(right)) return compare(left.getTime()/1000,Caster.toDoubleValue(right)); 478 DateTime dt=DateCaster.toDateAdvanced(right,DateCaster.CONVERTING_TYPE_OFFSET,null,null); 479 if(dt!=null) { 480 return compare(left.getTime()/1000,dt.getTime()/1000); 481 } 482 return Caster.toString(left).compareToIgnoreCase(right); 483 } 484 485 /** 486 * compares a Date with a double 487 * @param left 488 * @param right 489 * @return difference as int 490 */ 491 public static int compare(Date left, double right) { 492 return compare(left.getTime()/1000, DateTimeUtil.getInstance().toDateTime(right).getTime()/1000); 493 } 494 495 /** 496 * compares a Date with a boolean 497 * @param left 498 * @param right 499 * @return difference as int 500 */ 501 public static int compare(Date left, boolean right) { 502 return compare(left,right?1D:0D); 503 } 504 505 /** 506 * compares a Date with a Date 507 * @param left 508 * @param right 509 * @return difference as int 510 */ 511 public static int compare(Date left, Date right) { 512 return compare(left.getTime()/1000,right.getTime()/1000); 513 } 514 515 private static int error(boolean leftIsOk, boolean rightIsOk) throws ExpressionException { 516 // TODO remove this method 517 throw new ExpressionException("can't compare complex object types as simple value"); 518 } 519 520 /** 521 * Method to compare to different values, return true of objects are same otherwise false 522 * @param left left value to compare 523 * @param right right value to compare 524 * @param caseSensitive check case sensitive or not 525 * @return is same or not 526 * @throws PageException 527 */ 528 public static boolean equals(Object left, Object right, boolean caseSensitive) throws PageException { 529 if(caseSensitive) { 530 try { 531 return Caster.toString(left).equals(Caster.toString(right)); 532 } catch (ExpressionException e) { 533 return compare(left,right)==0; 534 } 535 } 536 return compare(left,right)==0; 537 } 538 539 public static boolean equalsEL(Object left, Object right, boolean caseSensitive, boolean allowComplexValues) { 540 if(!allowComplexValues || (Decision.isSimpleValue(left) && Decision.isSimpleValue(right))){ 541 try { 542 return equals(left, right, caseSensitive); 543 } catch (PageException e) { 544 return false; 545 } 546 } 547 return equalsComplexEL(left, right, caseSensitive,false); 548 } 549 550 public static boolean equalsComplexEL(Object left, Object right, boolean caseSensitive, boolean checkOnlyPublicAppearance) { 551 return _equalsComplexEL(null,left, right, caseSensitive,checkOnlyPublicAppearance); 552 } 553 554 public static boolean _equalsComplexEL(Set<Object> done,Object left, Object right, boolean caseSensitive, boolean checkOnlyPublicAppearance) { 555 if(left==right) return true; 556 if(Decision.isSimpleValue(left) && Decision.isSimpleValue(right)){ 557 try { 558 return equals(left, right, caseSensitive); 559 } catch (PageException e) { 560 return false; 561 } 562 } 563 if(left==null) return right==null; 564 565 if(done==null)done=new HashSet<Object>(); 566 else if(done.contains(left) && done.contains(right)) return true; 567 done.add(left); 568 done.add(right); 569 570 if(left instanceof Component && right instanceof Component) 571 return __equalsComplexEL(done,(Component)left, (Component)right,caseSensitive,checkOnlyPublicAppearance); 572 573 if(left instanceof UDFPlus && right instanceof UDFPlus) 574 return __equalsComplexEL(done,(UDFPlus)left, (UDFPlus)right,caseSensitive,checkOnlyPublicAppearance); 575 576 if(left instanceof Collection && right instanceof Collection) 577 return __equalsComplexEL(done,(Collection)left, (Collection)right,caseSensitive,checkOnlyPublicAppearance); 578 579 if(left instanceof List && right instanceof List) 580 return __equalsComplexEL(done,ListAsArray.toArray((List)left), ListAsArray.toArray((List)right),caseSensitive,checkOnlyPublicAppearance); 581 582 if(left instanceof Map && right instanceof Map) 583 return __equalsComplexEL(done,MapAsStruct.toStruct((Map)left,true), MapAsStruct.toStruct((Map)right,true),caseSensitive,checkOnlyPublicAppearance); 584 return left.equals(right); 585 } 586 587 private static boolean __equalsComplexEL(Set<Object> done,UDFPlus left, UDFPlus right,boolean caseSensitive, boolean checkOnlyPublicAppearance) { 588 if(left==null || right==null) { 589 if(left==right) return true; 590 return false; 591 } 592 if(!left.getPageSource().equals(right.getPageSource())) return false; 593 if(left.getIndex()!=right.getIndex()) return false; 594 595 return true; 596 } 597 598 private static boolean __equalsComplexEL(Set<Object> done,Component left, Component right,boolean caseSensitive, boolean checkOnlyPublicAppearance) { 599 if(left==null || right==null) { 600 if(left==right) return true; 601 return false; 602 } 603 if(!left.getPageSource().equals(right.getPageSource())) return false; 604 if(!checkOnlyPublicAppearance && !__equalsComplexEL(done,left.getComponentScope(),right.getComponentScope(), caseSensitive,checkOnlyPublicAppearance)) return false; 605 if(!__equalsComplexEL(done,(Collection)left,(Collection)right, caseSensitive,checkOnlyPublicAppearance)) return false; 606 return true; 607 } 608 609 private static boolean __equalsComplexEL(Set<Object> done,Collection left, Collection right,boolean caseSensitive, boolean checkOnlyPublicAppearance) { 610 if(left.size()!=right.size()) return false; 611 Iterator<Key> it = left.keyIterator(); 612 Key k; 613 Object l,r; 614 while(it.hasNext()){ 615 k=it.next(); 616 l=left.get(k,NULL); 617 r=right.get(k,NULL); 618 if(l==NULL || r==NULL) { 619 if(l==r) continue; 620 return false; 621 } 622 623 if(!_equalsComplexEL(done,r, l, caseSensitive,checkOnlyPublicAppearance)) { 624 return false; 625 } 626 } 627 return true; 628 } 629 630 631 public static boolean equals(Object left, Object right, boolean caseSensitive, boolean allowComplexValues) throws PageException { 632 if(!allowComplexValues || (Decision.isSimpleValue(left) && Decision.isSimpleValue(right))) 633 return equals(left, right, caseSensitive); 634 return equalsComplex(left, right, caseSensitive); 635 } 636 637 public static boolean equalsComplex(Object left, Object right, boolean caseSensitive) throws PageException { 638 return _equalsComplex(null,left, right, caseSensitive); 639 } 640 641 642 public static boolean _equalsComplex(Set<Object> done,Object left, Object right, boolean caseSensitive) throws PageException { 643 if(Decision.isSimpleValue(left) && Decision.isSimpleValue(right)){ 644 return equals(left, right, caseSensitive); 645 } 646 if(left==null) return right==null; 647 if(done==null)done=new HashSet<Object>(); 648 else if(done.contains(left) && done.contains(right)) return true; 649 done.add(left); 650 done.add(right); 651 652 if(left instanceof Collection && right instanceof Collection) 653 return __equalsComplex(done,(Collection)left, (Collection)right,caseSensitive); 654 655 if(left instanceof List && right instanceof List) 656 return __equalsComplex(done,ListAsArray.toArray((List)left), ListAsArray.toArray((List)right),caseSensitive); 657 658 if(left instanceof Map && right instanceof Map) 659 return __equalsComplex(done,MapAsStruct.toStruct((Map)left,true), MapAsStruct.toStruct((Map)right,true),caseSensitive); 660 661 return left.equals(right); 662 } 663 664 private static boolean __equalsComplex(Set<Object> done,Collection left, Collection right,boolean caseSensitive) throws PageException { 665 if(left.size()!=right.size()) return false; 666 Iterator<Key> it = left.keyIterator(); 667 Key k; 668 Object l,r; 669 while(it.hasNext()){ 670 k=it.next(); 671 r=right.get(k,NULL); 672 if(r==NULL) return false; 673 l=left.get(k,NULL); 674 if(!_equalsComplex(done,r, l, caseSensitive)) return false; 675 } 676 return true; 677 } 678 679 /** 680 * check if left is inside right (String-> ignore case) 681 * @param left string to check 682 * @param right substring to find in string 683 * @return return if substring has been found 684 * @throws PageException 685 */ 686 public static boolean ct(Object left, Object right) throws PageException { 687 return Caster.toString(left).toLowerCase().indexOf(Caster.toString(right).toLowerCase())!=-1; 688 } 689 690 /** 691 * Equivalence: Return True if both operands are True or both are False. The EQV operator is the opposite of the XOR operator. For example, True EQV True is True, but True EQV False is False. 692 * @param left value to check 693 * @param right value to check 694 * @return result of operation 695 * @throws PageException 696 */ 697 public static boolean eqv(Object left, Object right) throws PageException { 698 return eqv(Caster.toBooleanValue(left),Caster.toBooleanValue(right)); 699 } 700 701 /** 702 * Equivalence: Return True if both operands are True or both are False. The EQV operator is the opposite of the XOR operator. For example, True EQV True is True, but True EQV False is False. 703 * @param left value to check 704 * @param right value to check 705 * @return result of operation 706 */ 707 public static boolean eqv(boolean left, boolean right) { 708 return (left==true && right==true) || (left==false && right==false); 709 } 710 711 /** 712 * Implication: The statement A IMP B is the equivalent of the logical statement 713 * "If A Then B." A IMP B is False only if A is True and B is False. It is True in all other cases. 714 * @param left value to check 715 * @param right value to check 716 * @return result 717 * @throws PageException 718 */ 719 public static boolean imp(Object left, Object right) throws PageException { 720 return imp(Caster.toBooleanValue(left),Caster.toBooleanValue(right)); 721 } 722 723 /** 724 * Implication: The statement A IMP B is the equivalent of the logical statement 725 * "If A Then B." A IMP B is False only if A is True and B is False. It is True in all other cases. 726 * @param left value to check 727 * @param right value to check 728 * @return result 729 */ 730 public static boolean imp(boolean left, boolean right) { 731 return !(left==true && right==false); 732 } 733 734 /** 735 * check if left is not inside right (String-> ignore case) 736 * @param left string to check 737 * @param right substring to find in string 738 * @return return if substring NOT has been found 739 * @throws PageException 740 */ 741 public static boolean nct(Object left, Object right) throws PageException { 742 return !ct(left,right); 743 } 744 745 746 /** 747 * simple reference compersion 748 * @param left 749 * @param right 750 * @return 751 * @throws PageException 752 */ 753 public static boolean eeq(Object left, Object right) throws PageException { 754 return left==right; 755 } 756 757 758 /** 759 * simple reference compersion 760 * @param left 761 * @param right 762 * @return 763 * @throws PageException 764 */ 765 public static boolean neeq(Object left, Object right) throws PageException { 766 return left!=right; 767 } 768 769 /** 770 * calculate the exponent of the left value 771 * @param left value to get exponent from 772 * @param right exponent count 773 * @return return expoinended value 774 * @throws PageException 775 */ 776 public static double exponent(Object left, Object right) throws PageException { 777 return StrictMath.pow(Caster.toDoubleValue(left),Caster.toDoubleValue(right)); 778 } 779 780 public static double exponent(double left, double right) { 781 return StrictMath.pow(left,right); 782 } 783 784 public static double intdiv(double left, double right) { 785 return ((int)left)/((int)right); 786 } 787 788 public static double div(double left, double right) { 789 if(right==0d) 790 throw new ArithmeticException("Division by zero is not possible"); 791 return left/right; 792 } 793 794 public static float exponent(float left, float right) { 795 return (float) StrictMath.pow(left,right); 796 } 797 798 799 /** 800 * concat 2 CharSequences 801 * @param left 802 * @param right 803 * @return concated String 804 */ 805 public static CharSequence concat(CharSequence left, CharSequence right) { 806 if(left instanceof Appendable) { 807 try { 808 ((Appendable)left).append(right); 809 return left; 810 } catch (IOException e) {} 811 } 812 return new StringBuilder(left).append(right); 813 } 814 815 /** 816 * plus operation 817 * @param left 818 * @param right 819 * @return result of the opertions 820 */ 821 public final static double plus(double left, double right) { 822 return left+right; 823 } 824 825 /** 826 * minus operation 827 * @param left 828 * @param right 829 * @return result of the opertions 830 */ 831 public static double minus(double left, double right) { 832 return left-right; 833 } 834 835 /** 836 * modulus operation 837 * @param left 838 * @param right 839 * @return result of the opertions 840 */ 841 public static double modulus(double left, double right) { 842 return left%right; 843 } 844 845 /** 846 * divide operation 847 * @param left 848 * @param right 849 * @return result of the opertions 850 */ 851 public static double divide(double left, double right) { 852 return left/right; 853 } 854 855 /** 856 * multiply operation 857 * @param left 858 * @param right 859 * @return result of the opertions 860 */ 861 public static double multiply(double left, double right) { 862 return left*right; 863 } 864 865 /** 866 * bitand operation 867 * @param left 868 * @param right 869 * @return result of the opertions 870 */ 871 public static double bitand(double left, double right) { 872 return (int)left&(int)right; 873 } 874 875 /** 876 * bitand operation 877 * @param left 878 * @param right 879 * @return result of the opertions 880 */ 881 public static double bitor(double left, double right) { 882 return (int)left|(int)right; 883 } 884 885 886 public static Double divRef(Object left, Object right) throws PageException { 887 double r = Caster.toDoubleValue(right); 888 if(r==0d) 889 throw new ArithmeticException("Division by zero is not possible"); 890 return Caster.toDouble(Caster.toDoubleValue(left)/r); 891 } 892 893 public static Double exponentRef(Object left, Object right) throws PageException { 894 return Caster.toDouble(StrictMath.pow(Caster.toDoubleValue(left),Caster.toDoubleValue(right))); 895 } 896 897 public static Double intdivRef(Object left, Object right) throws PageException { 898 return Caster.toDouble(Caster.toIntValue(left)/Caster.toIntValue(right)); 899 } 900 901 public static Double plusRef(Object left, Object right) throws PageException { 902 return Caster.toDouble(Caster.toDoubleValue(left)+Caster.toDoubleValue(right)); 903 } 904 905 public static Double minusRef(Object left, Object right) throws PageException { 906 return Caster.toDouble(Caster.toDoubleValue(left)-Caster.toDoubleValue(right)); 907 } 908 909 public static Double modulusRef(Object left, Object right) throws PageException { 910 double rightAsDouble = Caster.toDoubleValue(right); 911 if(rightAsDouble==0d) 912 throw new ArithmeticException("Division by zero is not possible"); 913 return Caster.toDouble(Caster.toDoubleValue(left)%rightAsDouble); 914 } 915 916 public static Double divideRef(Object left, Object right) throws PageException { 917 return Caster.toDouble(Caster.toDoubleValue(left)/Caster.toDoubleValue(right)); 918 } 919 920 public static Double multiplyRef(Object left, Object right) throws PageException { 921 return Caster.toDouble(Caster.toDoubleValue(left)*Caster.toDoubleValue(right)); 922 } 923 924// post plus 925 public static Double unaryPostPlus(PageContext pc,Collection.Key[] keys,double value) throws PageException { 926 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 927 double rtn=Caster.toDoubleValue(ref.get(pc)); 928 ref.set(rtn+value); 929 return rtn; 930 } 931 public static Double unaryPostPlus(Collection coll,Collection.Key key,double value) throws PageException { 932 double rtn = Caster.toDoubleValue(coll.get(key)); 933 coll.set(key, rtn+value); 934 return rtn; 935 } 936 public static double unaryPoPl(PageContext pc,Collection.Key[] keys,double value) throws PageException { 937 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 938 double rtn=Caster.toDoubleValue(ref.get(pc)); 939 ref.set(rtn+value); 940 return rtn; 941 } 942 public static double unaryPoPl(PageContext pc,Collection.Key key,double value) throws PageException { 943 return unaryPoPl(pc.undefinedScope(),key,value); 944 } 945 public static double unaryPoPl(Collection coll,Collection.Key key,double value) throws PageException { 946 double rtn = Caster.toDoubleValue(coll.get(key)); 947 coll.set(key, rtn+value); 948 return rtn; 949 } 950 951 952 953// post minus 954 public static Double unaryPostMinus(PageContext pc,Collection.Key[] keys,double value) throws PageException { 955 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 956 double rtn=Caster.toDoubleValue(ref.get(pc)); 957 ref.set(rtn-value); 958 return rtn; 959 } 960 public static Double unaryPostMinus(Collection coll,Collection.Key key,double value) throws PageException { 961 double rtn = Caster.toDoubleValue(coll.get(key)); 962 coll.set(key, rtn-value); 963 return rtn; 964 } 965 public static double unaryPoMi(PageContext pc,Collection.Key[] keys,double value) throws PageException { 966 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 967 double rtn=Caster.toDoubleValue(ref.get(pc)); 968 ref.set(rtn-value); 969 return rtn; 970 } 971 public static double unaryPoMi(PageContext pc,Collection.Key key,double value) throws PageException { 972 return unaryPoMi(pc.undefinedScope(),key,value); 973 } 974 public static double unaryPoMi(Collection coll,Collection.Key key,double value) throws PageException { 975 double rtn = Caster.toDoubleValue(coll.get(key)); 976 coll.set(key, rtn-value); 977 return rtn; 978 } 979 980// pre plus 981 public static Double unaryPrePlus(PageContext pc,Collection.Key[] keys,double value) throws PageException { 982 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 983 double rtn=Caster.toDoubleValue(ref.get(pc))+value; 984 ref.set(rtn); 985 return rtn; 986 } 987 public static Double unaryPrePlus(Collection coll,Collection.Key key,double value) throws PageException { 988 double rtn = Caster.toDoubleValue(coll.get(key))+value; 989 coll.set(key, rtn); 990 return rtn; 991 } 992 public static double unaryPrPl(PageContext pc,Collection.Key[] keys,double value) throws PageException { 993 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 994 double rtn=Caster.toDoubleValue(ref.get(pc))+value; 995 ref.set(rtn); 996 return rtn; 997 } 998 public static double unaryPrPl(PageContext pc,Collection.Key key,double value) throws PageException { 999 return unaryPrPl(pc.undefinedScope(),key,value); 1000 } 1001 public static double unaryPrPl(Collection coll,Collection.Key key,double value) throws PageException { 1002 double rtn = Caster.toDoubleValue(coll.get(key))+value; 1003 coll.set(key, rtn); 1004 return rtn; 1005 } 1006 1007// pre minus 1008 public static Double unaryPreMinus(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1009 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1010 double rtn=Caster.toDoubleValue(ref.get(pc))-value; 1011 ref.set(rtn); 1012 return rtn; 1013 } 1014 public static Double unaryPreMinus(Collection coll,Collection.Key key,double value) throws PageException { 1015 double rtn = Caster.toDoubleValue(coll.get(key))-value; 1016 coll.set(key, rtn); 1017 return rtn; 1018 } 1019 public static double unaryPrMi(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1020 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1021 double rtn=Caster.toDoubleValue(ref.get(pc))-value; 1022 ref.set(rtn); 1023 return rtn; 1024 } 1025 public static double unaryPrMi(PageContext pc,Collection.Key key,double value) throws PageException { 1026 return unaryPrMi(pc.undefinedScope(),key,value); 1027 } 1028 public static double unaryPrMi(Collection coll,Collection.Key key,double value) throws PageException { 1029 double rtn = Caster.toDoubleValue(coll.get(key))-value; 1030 coll.set(key, rtn); 1031 return rtn; 1032 } 1033 1034// pre multiply 1035 public static Double unaryPreMultiply(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1036 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1037 double rtn=Caster.toDoubleValue(ref.get(pc))*value; 1038 ref.set(rtn); 1039 return rtn; 1040 } 1041 public static Double unaryPreMultiply(Collection coll,Collection.Key key,double value) throws PageException { 1042 double rtn = Caster.toDoubleValue(coll.get(key))*value; 1043 coll.set(key, rtn); 1044 return rtn; 1045 } 1046 public static double unaryPrMu(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1047 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1048 double rtn=Caster.toDoubleValue(ref.get(pc))*value; 1049 ref.set(rtn); 1050 return rtn; 1051 } 1052 public static double unaryPrMu(PageContext pc,Collection.Key key,double value) throws PageException { 1053 return unaryPrMu(pc.undefinedScope(),key,value); 1054 } 1055 public static double unaryPrMu(Collection coll,Collection.Key key,double value) throws PageException { 1056 double rtn = Caster.toDoubleValue(coll.get(key))*value; 1057 coll.set(key, rtn); 1058 return rtn; 1059 } 1060 1061// pre divide 1062 public static Double unaryPreDivide(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1063 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1064 double rtn=Caster.toDoubleValue(ref.get(pc))/value; 1065 ref.set(rtn); 1066 return rtn; 1067 } 1068 public static Double unaryPreDivide(Collection coll,Collection.Key key,double value) throws PageException { 1069 double rtn = Caster.toDoubleValue(coll.get(key))/value; 1070 coll.set(key, rtn); 1071 return rtn; 1072 } 1073 public static double unaryPrDi(PageContext pc,Collection.Key[] keys,double value) throws PageException { 1074 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1075 double rtn=Caster.toDoubleValue(ref.get(pc))/value; 1076 ref.set(rtn); 1077 return rtn; 1078 } 1079 public static double unaryPrDi(PageContext pc,Collection.Key key,double value) throws PageException { 1080 return unaryPrDi(pc.undefinedScope(),key,value); 1081 } 1082 public static double unaryPrDi(Collection coll,Collection.Key key,double value) throws PageException { 1083 double rtn = Caster.toDoubleValue(coll.get(key))/value; 1084 coll.set(key, rtn); 1085 return rtn; 1086 } 1087 1088//Concat 1089 public static String unaryPreConcat(PageContext pc,Collection.Key[] keys,String value) throws PageException { 1090 VariableReference ref = VariableInterpreter.getVariableReference(pc, keys,true); 1091 String rtn=Caster.toString(ref.get(pc)).concat(value); 1092 ref.set(pc,rtn); 1093 return rtn; 1094 } 1095 public static String unaryPreConcat(Collection coll,Collection.Key key,String value) throws PageException { 1096 String rtn = Caster.toString(coll.get(key)).concat(value); 1097 coll.set(key, rtn); 1098 return rtn; 1099 } 1100 public static String unaryPreConcat(PageContext pc,Collection.Key key,String value) throws PageException { 1101 VariableReference ref = VariableInterpreter.getVariableReference(pc, key,true); 1102 String rtn=Caster.toString(ref.get(pc)).concat(value); 1103 ref.set(pc,rtn); 1104 return rtn; 1105 } 1106}