001/** 002 * To.java 003 * 004 * Copyright (c) 2004-2012, Nicole C. Tedesco. All rights reserved. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 007 * use this file except in compliance with the License. You may obtain a copy of 008 * the License at: 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 015 * License for the specific language governing permissions and limitations under 016 * the License. 017 */ 018 019package net.sf.jaccumulator.lex; 020 021import java.math.BigDecimal; 022import java.math.BigInteger; 023import java.text.NumberFormat; 024import java.text.ParseException; 025import java.util.HashMap; 026import java.util.Map; 027 028import net.sf.jaccumulator.ControlIntention; 029import net.sf.jaccumulator.Domain; 030import net.sf.jaccumulator.primitives.Primitive; 031import net.sf.jaccumulator.primitives.SealedPrimitive; 032import net.sf.jaccumulator.reals.SealedReal; 033import net.sf.jaccumulator.scalars.NumericPrecision; 034import net.sf.jaccumulator.scalars.SealedScalar; 035import net.sf.jaccumulator.texts.SealedText; 036 037/** 038 * Default text translation {@link Action actions} for {@link Primitive} signals 039 * of presumed text implementation 040 * 041 * @since JAccumulator 4.0 042 * @author Nicole Tedesco (<a 043 * href="mailto:nicole@tedesco.name">nicole@tedesco.name</a>) 044 */ 045public abstract class To 046 implements 047 PrimitiveAction<Primitive<?>> 048{ 049 private static final Map<CharSequence,Boolean> _theBooleanNames = new HashMap<CharSequence,Boolean>(); 050 private static final Map<CharSequence,Double> _theSpecialNames = new HashMap<CharSequence,Double>(); 051 052 public static final To PRIMITIVE = new ToPrimitive(); 053 public static final To REAL = new ToReal(); 054 public static final To SCALAR = new ToScalar(); 055 056 public static final long ZERO_DOUBLE_LONG_BITS = Double.doubleToLongBits(0.0D); 057 public static final int ZERO_FLOAT_INT_BITS = Float.floatToIntBits(0.0F); 058 public static final Integer ZEROI = Integer.valueOf(0); 059 060 static { 061 _theBooleanNames.put(String.valueOf(true).toLowerCase(), Boolean.TRUE); 062 _theBooleanNames.put(String.valueOf(false).toLowerCase(), Boolean.FALSE); 063 _theSpecialNames.put(null, Double.NaN); 064 _theSpecialNames.put(String.valueOf((Object)null).toLowerCase(), 065 Double.NaN); 066 _theSpecialNames.put(String.valueOf(Double.NaN).toLowerCase(), 067 Double.NaN); 068 _theSpecialNames.put( 069 String.valueOf(Double.NEGATIVE_INFINITY).toLowerCase(), 070 Double.NEGATIVE_INFINITY); 071 _theSpecialNames.put( 072 String.valueOf(Double.POSITIVE_INFINITY).toLowerCase(), 073 Double.POSITIVE_INFINITY); 074 } 075 076 private To() 077 { 078 } 079 080 @Override 081 public boolean isCompositeAction() 082 { 083 return false; 084 } 085 086 @Override 087 public boolean isSimpleAction() 088 { 089 return true; 090 } 091 092 @Override 093 public ControlIntention reactToNull( final Primitive<?> aModel ) 094 { 095 aModel.assertDomain(Domain.EMPTY); 096 return ControlIntention.SUCCESS; 097 } 098 099 @Override 100 public ControlIntention reactToPrimitive( 101 final SealedPrimitive<?> aSignal, 102 final Primitive<?> aModel ) 103 { 104 return this.reactToScalar(aSignal, aModel); 105 } 106 107 @Override 108 public ControlIntention reactToReal( 109 final BigDecimal aSignal, 110 final Primitive<?> aModel ) 111 { 112 aModel.setScalar(aSignal.doubleValue()); 113 return ControlIntention.SUCCESS; 114 } 115 116 @Override 117 public ControlIntention reactToReal( 118 final BigInteger aSignal, 119 final Primitive<?> aModel ) 120 { 121 aModel.setScalar(aSignal.doubleValue()); 122 return ControlIntention.SUCCESS; 123 } 124 125 @Override 126 public ControlIntention reactToReal( 127 final SealedReal<?> aSignal, 128 final Primitive<?> aModel ) 129 { 130 return this.reactToScalar(aSignal, aModel); 131 } 132 133 @Override 134 public ControlIntention reactToScalar( 135 final boolean aSignal, 136 final Primitive<?> aModel ) 137 { 138 aModel.setScalar(aSignal); 139 return ControlIntention.SUCCESS; 140 } 141 142 @Override 143 public ControlIntention reactToScalar( 144 final byte aSignal, 145 final Primitive<?> aModel ) 146 { 147 aModel.setScalar(aSignal); 148 return ControlIntention.SUCCESS; 149 } 150 151 @Override 152 public ControlIntention reactToScalar( 153 final char aSignal, 154 final Primitive<?> aModel ) 155 { 156 aModel.setScalar(aSignal); 157 return ControlIntention.SUCCESS; 158 } 159 160 @Override 161 public ControlIntention reactToScalar( 162 final double aSignal, 163 final Primitive<?> aModel ) 164 { 165 aModel.setScalar(aSignal); 166 return ControlIntention.SUCCESS; 167 } 168 169 @Override 170 public ControlIntention reactToScalar( 171 final float aSignal, 172 final Primitive<?> aModel ) 173 { 174 aModel.setScalar(aSignal); 175 return ControlIntention.SUCCESS; 176 } 177 178 @Override 179 public ControlIntention reactToScalar( 180 final int aSignal, 181 final Primitive<?> aModel ) 182 { 183 aModel.setScalar(aSignal); 184 return ControlIntention.SUCCESS; 185 } 186 187 @Override 188 public ControlIntention reactToScalar( 189 final long aSignal, 190 final Primitive<?> aModel ) 191 { 192 aModel.setScalar(aSignal); 193 return ControlIntention.SUCCESS; 194 } 195 196 @Override 197 public ControlIntention reactToScalar( 198 final SealedScalar<?> aSignal, 199 final Primitive<?> aModel ) 200 { 201 aModel.setScalar(aSignal); 202 return ControlIntention.SUCCESS; 203 } 204 205 @Override 206 public ControlIntention reactToScalar( 207 final short aSignal, 208 final Primitive<?> aModel ) 209 { 210 aModel.setScalar(aSignal); 211 return ControlIntention.SUCCESS; 212 } 213 214 @Override 215 public ControlIntention reactToText( 216 final SealedText<?> aSignal, 217 final Primitive<?> aModel ) 218 { 219 return this.reactToText((CharSequence)aSignal.toString(), aModel); 220 } 221 222 @Override 223 public ControlIntention reactToText( 224 final String aSignal, 225 final Primitive<?> aModel ) 226 { 227 return this.reactToText((CharSequence)aSignal, aModel); 228 } 229 230 public static final boolean booleanValue( final BigDecimal aValue ) 231 { 232 return aValue.signum() != 0; 233 } 234 235 public static final boolean booleanValue( final BigInteger aValue ) 236 { 237 return aValue.signum() != 0; 238 } 239 240 public static final boolean booleanValue( final byte aValue ) 241 { 242 return aValue != (byte)0; 243 } 244 245 public static final boolean booleanValue( final char aValue ) 246 { 247 return aValue != (char)0; 248 } 249 250 public static final boolean booleanValue( final double aValue ) 251 { 252 return Double.doubleToLongBits(aValue) != ZERO_DOUBLE_LONG_BITS; 253 } 254 255 public static final boolean booleanValue( final float aValue ) 256 { 257 return Float.floatToIntBits(aValue) != ZERO_FLOAT_INT_BITS; 258 } 259 260 public static final boolean booleanValue( final int aValue ) 261 { 262 return aValue != 0; 263 } 264 265 public static final boolean booleanValue( final long aValue ) 266 { 267 return aValue != 0; 268 } 269 270 public static final boolean booleanValue( final short aValue ) 271 { 272 return aValue != (short)0; 273 } 274 275 public static final boolean booleanValueFromNumber( final Number aNumber ) 276 { 277 final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber); 278 switch (prec) { 279 case BYTE: 280 return booleanValue(aNumber.byteValue()); 281 case SHORT: 282 return booleanValue(aNumber.shortValue()); 283 case INTEGER: 284 return booleanValue(aNumber.intValue()); 285 case LONG: 286 return booleanValue(aNumber.longValue()); 287 case FLOAT: 288 return booleanValue(aNumber.floatValue()); 289 case DOUBLE: 290 return booleanValue(aNumber.doubleValue()); 291 case UNLIMITED_INTEGER: 292 try { 293 final BigInteger ui = (BigInteger)aNumber; 294 return booleanValue(ui); 295 } catch (final ClassCastException ex) { 296 } 297 break; 298 case UNLIMITED_DECIMAL: 299 try { 300 final BigDecimal ud = (BigDecimal)aNumber; 301 return booleanValue(ud); 302 } catch (final ClassCastException ex) { 303 } 304 break; 305 } 306 return false; 307 } 308 309 public static final boolean booleanValueFromText( final CharSequence p0 ) 310 { 311 final String myString = p0.toString(); 312 final String myStringLower = myString.toLowerCase(); 313 final Boolean aBoolean = getSpecialBoolean(myStringLower); 314 if (aBoolean != null) return aBoolean; 315 final Double aDouble = getSpecialDouble(myStringLower); 316 if (aDouble != null) 317 return Double.doubleToLongBits(aDouble) != ZERO_DOUBLE_LONG_BITS; 318 try { 319 final Number aNumber = NumberFormat.getNumberInstance().parse( 320 myString); 321 return booleanValueFromNumber(aNumber); 322 } catch (final ParseException ex) { 323 } 324 try { 325 final BigDecimal ud = new BigDecimal(myString); 326 return booleanValue(ud); 327 } catch (final NumberFormatException ex) { 328 } 329 return false; 330 } 331 332 public static final byte byteValue( final boolean aValue ) 333 { 334 return aValue ? (byte)1 : (byte)0; 335 } 336 337 public static final char charValue( final boolean aValue ) 338 { 339 return aValue ? (char)1 : (char)0; 340 } 341 342 public static final double doubleValue( final boolean aValue ) 343 { 344 return aValue ? (double)1 : (double)0; 345 } 346 347 public static final float floatValue( final boolean aValue ) 348 { 349 return aValue ? (float)1 : (float)0; 350 } 351 352 public static final Boolean getSpecialBoolean( final CharSequence aName ) 353 { 354 return _theBooleanNames.get(aName); 355 } 356 357 public static final Boolean getSpecialBooleanIgnoreCase( 358 final CharSequence aName ) 359 { 360 return getSpecialBoolean(aName.toString().toLowerCase()); 361 } 362 363 /** 364 * Answer the {@link Double} value associated with the specified symbolic 365 * name, or answer {@code null} if no such symbol had been defined 366 * 367 * @param aName 368 * a symbolic name 369 * @return a {@link Double} associated with the symbolic name, or 370 * {@code null} if no such symbol had been defined 371 */ 372 public static final Double getSpecialDouble( final CharSequence aName ) 373 { 374 return _theSpecialNames.get(aName); 375 } 376 377 /** 378 * Answer the {@link Double} value associated with the specified case 379 * insensitive symbolic name, or answer {@code null} if no such symbol had 380 * been defined 381 * 382 * @param aName 383 * a symbolic name 384 * @return a {@link Double} associated with the symbolic name, or 385 * {@code null} if no such symbol had been defined 386 */ 387 public static final Double getSpecialDoubleIgnoreCase( 388 final CharSequence aName ) 389 { 390 return getSpecialDouble(aName.toString().toLowerCase()); 391 } 392 393 public static final int intValue( final boolean aValue ) 394 { 395 return aValue ? (int)1 : (int)0; 396 } 397 398 public static final long longValue( final boolean aValue ) 399 { 400 return aValue ? (long)1 : (long)0; 401 } 402 403 public static final short shortValue( final boolean aValue ) 404 { 405 return aValue ? (short)1 : (short)0; 406 } 407 408 public static final Number toNumber( 409 final CharSequence aValue, 410 final Number aDefault ) 411 { 412 final String aString = aValue.toString(); 413 final Double aDouble = getSpecialDoubleIgnoreCase(aValue); 414 if (aDouble != null) return aDouble; 415 try { 416 final Number aNumber = NumberFormat.getNumberInstance().parse( 417 aString); 418 return aNumber; 419 } catch (final ParseException ex) { 420 } 421 try { 422 final Number aNumber = new BigDecimal(aString); 423 return aNumber; 424 } catch (final NumberFormatException ex) { 425 } 426 return aDefault; 427 } 428 429 protected static class ToPrimitive 430 extends 431 ToReal 432 { 433 public ToPrimitive() 434 { 435 } 436 437 @Override 438 public ControlIntention reactToPrimitive( 439 final SealedPrimitive<?> aSignal, 440 final Primitive<?> aModel ) 441 { 442 aModel.setPrimitive(aSignal); 443 return ControlIntention.SUCCESS; 444 } 445 446 @Override 447 public ControlIntention reactToText( 448 final CharSequence aSignal, 449 final Primitive<?> aModel ) 450 { 451 final Number aNumber = toNumber(aSignal, null); 452 if (aNumber != null) { 453 final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber); 454 switch (prec) { 455 case UNLIMITED_DECIMAL: 456 final BigDecimal ud = (BigDecimal)aNumber; 457 aModel.setReal(ud); 458 break; 459 case UNLIMITED_INTEGER: 460 final BigInteger ui = (BigInteger)aNumber; 461 aModel.setReal(ui); 462 break; 463 case BYTE: 464 aModel.setScalar(aNumber.byteValue()); 465 break; 466 case SHORT: 467 aModel.setScalar(aNumber.shortValue()); 468 break; 469 case LONG: 470 aModel.setScalar(aNumber.longValue()); 471 break; 472 case FLOAT: 473 aModel.setScalar(aNumber.floatValue()); 474 break; 475 case DOUBLE: 476 aModel.setScalar(aNumber.doubleValue()); 477 break; 478 default: 479 aModel.setScalar(aNumber.intValue()); 480 break; 481 } 482 return ControlIntention.SUCCESS; 483 } 484 final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal); 485 if (aBoolean != null) { 486 aModel.setScalar(aBoolean); 487 } else { 488 aModel.setText(aSignal); 489 } 490 return ControlIntention.SUCCESS; 491 } 492 493 @Override 494 public String toString() 495 { 496 return "ToReal(CharSequence)"; 497 } 498 } 499 500 protected static class ToReal 501 extends 502 ToScalar 503 { 504 public ToReal() 505 { 506 } 507 508 @Override 509 public ControlIntention reactToPrimitive( 510 final SealedPrimitive<?> aSignal, 511 final Primitive<?> aModel ) 512 { 513 return this.reactToReal(aSignal, aModel); 514 } 515 516 @Override 517 public ControlIntention reactToText( 518 final CharSequence aSignal, 519 final Primitive<?> aModel ) 520 { 521 final Number aNumber = toNumber(aSignal, null); 522 if (aNumber != null) { 523 final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber); 524 switch (prec) { 525 case UNLIMITED_DECIMAL: 526 final BigDecimal ud = (BigDecimal)aNumber; 527 aModel.setReal(ud); 528 break; 529 case UNLIMITED_INTEGER: 530 final BigInteger ui = (BigInteger)aNumber; 531 aModel.setReal(ui); 532 break; 533 case BYTE: 534 aModel.setScalar(aNumber.byteValue()); 535 break; 536 case SHORT: 537 aModel.setScalar(aNumber.shortValue()); 538 break; 539 case LONG: 540 aModel.setScalar(aNumber.longValue()); 541 break; 542 case FLOAT: 543 aModel.setScalar(aNumber.floatValue()); 544 break; 545 case DOUBLE: 546 aModel.setScalar(aNumber.doubleValue()); 547 break; 548 default: 549 aModel.setScalar(aNumber.intValue()); 550 break; 551 } 552 return ControlIntention.SUCCESS; 553 } 554 final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal); 555 if (aBoolean != null) { 556 aModel.setScalar(aBoolean); 557 return ControlIntention.SUCCESS; 558 } 559 return ControlIntention.REJECT; 560 } 561 562 @Override 563 public String toString() 564 { 565 return "ToReal(CharSequence)"; 566 } 567 } 568 569 protected static class ToScalar 570 extends 571 To 572 { 573 public ToScalar() 574 { 575 } 576 577 @Override 578 public ControlIntention reactToNull( final Primitive<?> aModel ) 579 { 580 aModel.assertDomain(Domain.EMPTY); 581 return ControlIntention.SUCCESS; 582 } 583 584 @Override 585 public ControlIntention reactToPrimitive( 586 final SealedPrimitive<?> aSignal, 587 final Primitive<?> aModel ) 588 { 589 return this.reactToScalar(aSignal, aModel); 590 } 591 592 @Override 593 public ControlIntention reactToReal( 594 final BigDecimal aSignal, 595 final Primitive<?> aModel ) 596 { 597 aModel.setScalar(aSignal.doubleValue()); 598 return ControlIntention.SUCCESS; 599 } 600 601 @Override 602 public ControlIntention reactToReal( 603 final BigInteger aSignal, 604 final Primitive<?> aModel ) 605 { 606 aModel.setScalar(aSignal.doubleValue()); 607 return ControlIntention.SUCCESS; 608 } 609 610 @Override 611 public ControlIntention reactToReal( 612 final SealedReal<?> aSignal, 613 final Primitive<?> aModel ) 614 { 615 return this.reactToScalar(aSignal, aModel); 616 } 617 618 @Override 619 public ControlIntention reactToScalar( 620 final boolean aSignal, 621 final Primitive<?> aModel ) 622 { 623 aModel.setScalar(aSignal); 624 return ControlIntention.SUCCESS; 625 } 626 627 @Override 628 public ControlIntention reactToScalar( 629 final byte aSignal, 630 final Primitive<?> aModel ) 631 { 632 aModel.setScalar(aSignal); 633 return ControlIntention.SUCCESS; 634 } 635 636 @Override 637 public ControlIntention reactToScalar( 638 final char aSignal, 639 final Primitive<?> aModel ) 640 { 641 aModel.setScalar(aSignal); 642 return ControlIntention.SUCCESS; 643 } 644 645 @Override 646 public ControlIntention reactToScalar( 647 final double aSignal, 648 final Primitive<?> aModel ) 649 { 650 aModel.setScalar(aSignal); 651 return ControlIntention.SUCCESS; 652 } 653 654 @Override 655 public ControlIntention reactToScalar( 656 final float aSignal, 657 final Primitive<?> aModel ) 658 { 659 aModel.setScalar(aSignal); 660 return ControlIntention.SUCCESS; 661 } 662 663 @Override 664 public ControlIntention reactToScalar( 665 final int aSignal, 666 final Primitive<?> aModel ) 667 { 668 aModel.setScalar(aSignal); 669 return ControlIntention.SUCCESS; 670 } 671 672 @Override 673 public ControlIntention reactToScalar( 674 final long aSignal, 675 final Primitive<?> aModel ) 676 { 677 aModel.setScalar(aSignal); 678 return ControlIntention.SUCCESS; 679 } 680 681 @Override 682 public ControlIntention reactToScalar( 683 final SealedScalar<?> aSignal, 684 final Primitive<?> aModel ) 685 { 686 aModel.setScalar(aSignal); 687 return ControlIntention.SUCCESS; 688 } 689 690 @Override 691 public ControlIntention reactToScalar( 692 final short aSignal, 693 final Primitive<?> aModel ) 694 { 695 aModel.setScalar(aSignal); 696 return ControlIntention.SUCCESS; 697 } 698 699 @Override 700 public ControlIntention reactToText( 701 final CharSequence aSignal, 702 final Primitive<?> aModel ) 703 { 704 final Number aNumber = toNumber(aSignal, null); 705 if (aNumber != null) { 706 final NumericPrecision prec = NumericPrecision.getPrecisionFor(aNumber); 707 switch (prec) { 708 case BYTE: 709 aModel.setScalar(aNumber.byteValue()); 710 break; 711 case SHORT: 712 aModel.setScalar(aNumber.shortValue()); 713 break; 714 case LONG: 715 aModel.setScalar(aNumber.longValue()); 716 break; 717 case FLOAT: 718 aModel.setScalar(aNumber.floatValue()); 719 break; 720 case UNLIMITED_INTEGER: 721 case UNLIMITED_DECIMAL: 722 case DOUBLE: 723 aModel.setScalar(aNumber.doubleValue()); 724 break; 725 default: 726 aModel.setScalar(aNumber.intValue()); 727 break; 728 } 729 return ControlIntention.SUCCESS; 730 } 731 final Boolean aBoolean = getSpecialBooleanIgnoreCase(aSignal); 732 if (aBoolean != null) { 733 aModel.setScalar(aBoolean); 734 return ControlIntention.SUCCESS; 735 } 736 return ControlIntention.REJECT; 737 } 738 739 @Override 740 public ControlIntention reactToText( 741 final SealedText<?> aSignal, 742 final Primitive<?> aModel ) 743 { 744 return this.reactToText((CharSequence)aSignal.toString(), aModel); 745 } 746 747 @Override 748 public ControlIntention reactToText( 749 final String aSignal, 750 final Primitive<?> aModel ) 751 { 752 return this.reactToText((CharSequence)aSignal, aModel); 753 } 754 755 @Override 756 public String toString() 757 { 758 return "ToScalar(CharSequence)"; 759 } 760 } 761 762 /** 763 * Format the {@link #toString() String} representation of the specified 764 * object in a manner appropriate for inclusion in collections. For 765 * instance, Strings (text) will be quoted. 766 * 767 * @param aPrimitive 768 * the Primitive to query 769 * @return formatted text 770 */ 771 public static final String toExternalString( final Primitive<?> aPrimitive ) 772 { 773 switch (aPrimitive.getDomain()) { 774 case TEXT: 775 return '"' + aPrimitive.toString() + '"'; 776 } 777 return aPrimitive.toString(); 778 } 779}