| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.debug.ui; | 5 package org.chromium.debug.ui; |
| 6 | 6 |
| 7 import java.lang.annotation.ElementType; |
| 8 import java.lang.annotation.Retention; |
| 9 import java.lang.annotation.RetentionPolicy; |
| 10 import java.lang.annotation.Target; |
| 11 import java.lang.reflect.InvocationTargetException; |
| 12 import java.lang.reflect.Method; |
| 13 import java.lang.reflect.ParameterizedType; |
| 14 import java.lang.reflect.Type; |
| 15 import java.lang.reflect.WildcardType; |
| 7 import java.util.ArrayList; | 16 import java.util.ArrayList; |
| 8 import java.util.Arrays; | 17 import java.util.Arrays; |
| 9 import java.util.Collection; | 18 import java.util.Collection; |
| 10 import java.util.Collections; | 19 import java.util.Collections; |
| 11 import java.util.Comparator; | 20 import java.util.Comparator; |
| 12 import java.util.HashMap; | 21 import java.util.HashMap; |
| 13 import java.util.HashSet; | 22 import java.util.HashSet; |
| 14 import java.util.LinkedHashMap; | 23 import java.util.LinkedHashMap; |
| 15 import java.util.LinkedHashSet; | 24 import java.util.LinkedHashSet; |
| 16 import java.util.List; | 25 import java.util.List; |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 * <p>Scope roughly corresponds to a group of UI controls that may become disa
bled, | 312 * <p>Scope roughly corresponds to a group of UI controls that may become disa
bled, |
| 304 * and thus may not generate any data and need no inner updates. | 313 * and thus may not generate any data and need no inner updates. |
| 305 */ | 314 */ |
| 306 public interface Scope { | 315 public interface Scope { |
| 307 Scope getOuterScope(); | 316 Scope getOuterScope(); |
| 308 | 317 |
| 309 /** | 318 /** |
| 310 * Creates a switcher that is operated by optional expression. | 319 * Creates a switcher that is operated by optional expression. |
| 311 * @param <T> type of expression | 320 * @param <T> type of expression |
| 312 */ | 321 */ |
| 313 <T> OptionalSwitcher<T> addOptionalSwitch(Gettable<? extends Optional<T>> ex
pression); | 322 <T> OptionalSwitcher<T> addOptionalSwitch(Gettable<? extends Optional<? exte
nds T>> expression); |
| 314 | 323 |
| 315 /** | 324 /** |
| 316 * Creates a switcher that is operated by non-optional expression. | 325 * Creates a switcher that is operated by non-optional expression. |
| 317 * @param <T> type of expression | 326 * @param <T> type of expression |
| 318 */ | 327 */ |
| 319 <T> Switcher<T> addSwitch(Gettable<T> expression); | 328 <T> Switcher<T> addSwitch(Gettable<T> expression); |
| 320 } | 329 } |
| 321 | 330 |
| 322 /** | 331 /** |
| 323 * A callback that lets UI to reflect that some scope became enabled/disabled. | 332 * A callback that lets UI to reflect that some scope became enabled/disabled. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 351 | 360 |
| 352 /** | 361 /** |
| 353 * A switcher that is operated by optional expression. | 362 * A switcher that is operated by optional expression. |
| 354 */ | 363 */ |
| 355 public interface OptionalSwitcher<T> extends SwitchBase<T> { | 364 public interface OptionalSwitcher<T> extends SwitchBase<T> { |
| 356 /** | 365 /** |
| 357 * See javadoc for {@link Switcher#createMerge}; the difference of this meth
od is that | 366 * See javadoc for {@link Switcher#createMerge}; the difference of this meth
od is that |
| 358 * all sources have optional type and the merge source itself of optional ty
pe. The switcher | 367 * all sources have optional type and the merge source itself of optional ty
pe. The switcher |
| 359 * expression may have error value, in this case the merger also returns thi
s error value. | 368 * expression may have error value, in this case the merger also returns thi
s error value. |
| 360 */ | 369 */ |
| 361 <P> ValueSource<? extends Optional<P>> createOptionalMerge( | 370 <P> ValueSource<? extends Optional<? extends P>> createOptionalMerge( |
| 362 ValueSource<? extends Optional<P>> ... sources); | 371 ValueSource<? extends Optional<? extends P>> ... sources); |
| 363 } | 372 } |
| 364 | 373 |
| 365 public static <T> ValueSource<T> createConstant(final T constnant, Updater upd
ater) { | 374 public static <T> ValueSource<T> createConstant(final T constnant, Updater upd
ater) { |
| 366 ValueSource<T> source = new ValueSource<T>() { | 375 ValueSource<T> source = new ValueSource<T>() { |
| 367 public T getValue() { | 376 public T getValue() { |
| 368 return constnant; | 377 return constnant; |
| 369 } | 378 } |
| 370 }; | 379 }; |
| 371 updater.addSource(updater.rootScope(), source); | 380 updater.addSource(updater.rootScope(), source); |
| 372 return source; | 381 return source; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 396 return new Optional<V>() { | 405 return new Optional<V>() { |
| 397 public Set<Message> errorMessages() { | 406 public Set<Message> errorMessages() { |
| 398 return Collections.emptySet(); | 407 return Collections.emptySet(); |
| 399 } | 408 } |
| 400 public V getNormal() { | 409 public V getNormal() { |
| 401 return value; | 410 return value; |
| 402 } | 411 } |
| 403 public boolean isNormal() { | 412 public boolean isNormal() { |
| 404 return true; | 413 return true; |
| 405 } | 414 } |
| 415 @Override |
| 416 public boolean equals(Object obj) { |
| 417 if (obj == null) { |
| 418 return false; |
| 419 } |
| 420 if (obj == this) { |
| 421 return true; |
| 422 } |
| 423 if (!obj.getClass().equals(this.getClass())) { |
| 424 return false; |
| 425 } |
| 426 Optional<?> other = (Optional<?>) obj; |
| 427 if (value == null) { |
| 428 return other.getNormal() == null; |
| 429 } else { |
| 430 return value.equals(other.getNormal()); |
| 431 } |
| 432 } |
| 433 @Override |
| 434 public int hashCode() { |
| 435 return value == null ? 0 : value.hashCode(); |
| 436 } |
| 406 }; | 437 }; |
| 407 } | 438 } |
| 408 | 439 |
| 409 public static <V> Optional<V> createErrorOptional(Message message) { | 440 public static <V> Optional<V> createErrorOptional(Message message) { |
| 410 return createErrorOptional(Collections.singleton(message)); | 441 return createErrorOptional(Collections.singleton(message)); |
| 411 } | 442 } |
| 412 | 443 |
| 413 public static <V> Optional<V> createErrorOptional(final Set<? extends Message>
messages) { | 444 public static <V> Optional<V> createErrorOptional(final Set<? extends Message>
messages) { |
| 414 return new Optional<V>() { | 445 return new Optional<V>() { |
| 415 public Set<? extends Message> errorMessages() { | 446 public Set<? extends Message> errorMessages() { |
| 416 return messages; | 447 return messages; |
| 417 } | 448 } |
| 418 public V getNormal() { | 449 public V getNormal() { |
| 419 throw new UnsupportedOperationException(); | 450 throw new UnsupportedOperationException(); |
| 420 } | 451 } |
| 421 public boolean isNormal() { | 452 public boolean isNormal() { |
| 422 return false; | 453 return false; |
| 423 } | 454 } |
| 455 @Override |
| 456 public boolean equals(Object obj) { |
| 457 if (obj == null) { |
| 458 return false; |
| 459 } |
| 460 if (obj == this) { |
| 461 return true; |
| 462 } |
| 463 if (!obj.getClass().equals(this.getClass())) { |
| 464 return false; |
| 465 } |
| 466 Optional<?> other = (Optional<?>) obj; |
| 467 if (messages == null) { |
| 468 return other.errorMessages() == null; |
| 469 } else { |
| 470 return messages.equals(other.errorMessages()); |
| 471 } |
| 472 } |
| 473 @Override |
| 474 public int hashCode() { |
| 475 return messages.hashCode(); |
| 476 } |
| 424 }; | 477 }; |
| 425 } | 478 } |
| 426 | 479 |
| 427 /** | 480 /** |
| 428 * A user interface message for dialog window. It has text and priority that h
elps choosing | 481 * A user interface message for dialog window. It has text and priority that h
elps choosing |
| 429 * the most important message it there are many of them. | 482 * the most important message it there are many of them. |
| 430 */ | 483 */ |
| 431 public static class Message { | 484 public static class Message { |
| 432 private final String text; | 485 private final String text; |
| 433 private final MessagePriority priority; | 486 private final MessagePriority priority; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 Optional<T> result = calculateNewValue(); | 548 Optional<T> result = calculateNewValue(); |
| 496 Optional<T> oldValue = getValue(); | 549 Optional<T> oldValue = getValue(); |
| 497 setCurrentValue(result); | 550 setCurrentValue(result); |
| 498 if (!result.equals(oldValue)) { | 551 if (!result.equals(oldValue)) { |
| 499 updater.reportChanged(this); | 552 updater.reportChanged(this); |
| 500 } | 553 } |
| 501 } | 554 } |
| 502 } | 555 } |
| 503 | 556 |
| 504 /** | 557 /** |
| 505 * An interface similar to {@link Gettable}, but with a quite specific contrac
t: | 558 * An expression that gets calculated only when its dependencies are all non-e
rror. |
| 506 * it may depend on some optional values, but its calculate method should only
be called | 559 * The interface contains a "calculate" method and several methods that return
expression |
| 507 * when all of the values are normal (non-error). This way its implementations
becomes simpler. | 560 * dependencies. |
| 508 * It's up to someone who calls calculate method to check that contract is hel
d. | 561 * <p> |
| 562 * The one that is using this expression is responsible for reading all source
s, checking |
| 563 * whether the optional values are normal and calling "calculate" method passi
ng the |
| 564 * normal values as arguments. |
| 565 * <p> |
| 566 * The interface is reflection-oriented, as you cannot express type schema in
plain Java. |
| 567 * The client should check the interface for a type-consistency statically on
runtime and |
| 568 * throw exception if something is wrong. All user types are explicitly declar
ed in |
| 569 * signature of methods. This allows accurate type checking via reflection (in
cluding |
| 570 * generics parameters, which are otherwise erased on runtime). |
| 571 * <p> |
| 572 * The interface is reflection-based. It only contains annotation that method
should have. |
| 573 * |
| 574 * @param <T> type of value this expression returns |
| 509 */ | 575 */ |
| 510 public interface NormalExpression<RES> { | 576 public interface NormalExpression<T> { |
| 511 RES calculate(); | 577 /** |
| 578 * An annotation for a "calculate" method of the interface. There should be
only one such |
| 579 * a method in the object. Its return type should be "T" or "Optional<? exte
nds T>" (we are |
| 580 * flexible in this only place). It should have arguments one per its depend
ency |
| 581 * (in the same order). |
| 582 * <p>The method must be declared public for the reflection to work. |
| 583 */ |
| 584 @Retention(RetentionPolicy.RUNTIME) |
| 585 @Target(ElementType.METHOD) |
| 586 @interface Calculate { |
| 587 } |
| 588 |
| 589 /** |
| 590 * An annotation for a method that returns expression dependency. It should
have no arguments |
| 591 * and return IValueSource<? extends Optional<*T*>> type ("IValueSource" is
significant here). |
| 592 * The type *T* should correspond to the type of "calculate" method argument
(dependency |
| 593 * methods should go in the same order as "calculate" arguments go). |
| 594 * <p>The method must be declared public for the reflection to work. |
| 595 */ |
| 596 @Target(ElementType.METHOD) |
| 597 @Retention(RetentionPolicy.RUNTIME) |
| 598 @interface DependencyGetter { |
| 599 } |
| 512 } | 600 } |
| 513 | 601 |
| 602 |
| 514 /** | 603 /** |
| 515 * Creates a {@link ValueProcessor} that is backed by {@link NormalExpression}
. | 604 * Converts {@link NormalExpression} into {@link Gettable} and takes responsib
ility of checking |
| 516 * @param optionalSources list of inputs that are optional and thus have to be
checked for | 605 * that all dependencies have only normal values. Despite {@link NormalExpress
ion} being |
| 517 * {@link NormalExpression} contract. | 606 * reflection-based interface, this method should be completely type-safe for
a programmer and |
| 607 * accurately check (statically) that its signatures are consistent (including
generic types). |
| 518 */ | 608 */ |
| 519 public static <T> ValueProcessor<Optional<T>> createOptionalProcessor( | 609 public static <RES> Gettable<Optional<? extends RES>> handleErrors( |
| 520 final NormalExpression<T> expression, | 610 final NormalExpression<RES> expression) { |
| 521 ValueSource<? extends Optional<?>> ... optionalSources) { | 611 Class<?> expressionClass = expression.getClass(); |
| 522 final Gettable<Optional<T>> getter = handleErrors(expression, optionalSource
s); | 612 |
| 523 return createProcessor(getter); | 613 // All reflection is done in generic-aware API generation. |
| 524 } | 614 |
| 525 | 615 // Read generic NormalExpression type parameter of expression class. |
| 526 /** | 616 Type expressionType; |
| 527 * Implements the basic contract of {@link NormalExpression}. Wraps it as {@li
nk Gettable} and | 617 { |
| 528 * keeps all its optional sources that are checked before each calculation. | 618 ParameterizedType normalExpressionType = null; |
| 529 */ | 619 for (Type inter : expressionClass.getGenericInterfaces()) { |
| 530 public static <RES> Gettable<Optional<RES>> handleErrors(final NormalExpressio
n<RES> expression, | 620 if (inter instanceof ParameterizedType == false) { |
| 531 final ValueSource<? extends Optional<?>> ... optionalSources) { | 621 continue; |
| 532 NormalExpression<Optional<RES>> wrapper = new NormalExpression<Optional<RES>
>() { | 622 } |
| 533 public Optional<RES> calculate() { | 623 ParameterizedType parameterizedType = (ParameterizedType) inter; |
| 534 return createOptional(expression.calculate()); | 624 if (!parameterizedType.getRawType().equals(NormalExpression.class)) { |
| 625 continue; |
| 626 } |
| 627 normalExpressionType = parameterizedType; |
| 628 } |
| 629 if (normalExpressionType == null) { |
| 630 throw new IllegalArgumentException("Expression does not directly impleme
nt " + |
| 631 NormalExpression.class.getName()); |
| 632 } |
| 633 expressionType = normalExpressionType.getActualTypeArguments()[0]; |
| 634 } |
| 635 |
| 636 // Read all methods of expression class and choose annotated ones. |
| 637 Method calculateMethodVar = null; |
| 638 final List<Method> dependencyMethods = new ArrayList<Method>(2); |
| 639 for (Method m : expressionClass.getMethods()) { |
| 640 if (m.getAnnotation(NormalExpression.Calculate.class) != null) { |
| 641 if (calculateMethodVar != null) { |
| 642 throw new IllegalArgumentException("Class " + expressionClass.getName(
) + |
| 643 " has more than one method with " + |
| 644 NormalExpression.Calculate.class.getName() + " annotation"); |
| 645 } |
| 646 calculateMethodVar = m; |
| 647 } |
| 648 if (m.getAnnotation(NormalExpression.DependencyGetter.class) != null) { |
| 649 dependencyMethods.add(m); |
| 650 } |
| 651 } |
| 652 if (calculateMethodVar == null) { |
| 653 throw new IllegalArgumentException("Failed to found Class method with " + |
| 654 NormalExpression.Calculate.class.getName() + " annotation in " + |
| 655 expressionClass.getName()); |
| 656 } |
| 657 final Method calculateMethod = calculateMethodVar; |
| 658 Type methodReturnType = calculateMethod.getGenericReturnType(); |
| 659 |
| 660 // Method is typically in anonymous class. Making it accessible is required. |
| 661 calculateMethod.setAccessible(true); |
| 662 |
| 663 // Prepare handling method return value (it's either a plain value or an opt
ional wrapper). |
| 664 abstract class ReturnValueHandler { |
| 665 abstract Optional<? extends RES> castResult(Object resultObject); |
| 666 } |
| 667 |
| 668 final ReturnValueHandler returnValueHandler; |
| 669 |
| 670 if (methodReturnType.equals(expressionType)) { |
| 671 returnValueHandler = new ReturnValueHandler() { |
| 672 Optional<? extends RES> castResult(Object resultObject) { |
| 673 // Return type in interface is RES. |
| 674 // Type cast has been proven to be correct. |
| 675 return createOptional((RES) resultObject); |
| 676 } |
| 677 }; |
| 678 } else { |
| 679 tryUnwrapOptional: { |
| 680 if (methodReturnType instanceof ParameterizedType) { |
| 681 ParameterizedType parameterizedType = (ParameterizedType) methodReturn
Type; |
| 682 if (parameterizedType.getRawType() == Optional.class) { |
| 683 Type optionalParam = parameterizedType.getActualTypeArguments()[0]; |
| 684 boolean okToCast = false; |
| 685 if (optionalParam instanceof WildcardType) { |
| 686 WildcardType wildcardType = (WildcardType) optionalParam; |
| 687 if (wildcardType.getUpperBounds()[0].equals(expressionType)) { |
| 688 okToCast = true; |
| 689 } |
| 690 } else if (optionalParam.equals(expressionType)) { |
| 691 okToCast = true; |
| 692 } |
| 693 if (okToCast) { |
| 694 returnValueHandler = new ReturnValueHandler() { |
| 695 Optional<? extends RES> castResult(Object resultObject) { |
| 696 // Return type in interface is optional wrapper around RES. |
| 697 // Type cast has been proven to be correct. |
| 698 return (Optional<? extends RES>) resultObject; |
| 699 } |
| 700 }; |
| 701 break tryUnwrapOptional; |
| 702 } |
| 703 } |
| 704 } |
| 705 throw new IllegalArgumentException("Wrong return type " + methodReturnTy
pe + |
| 706 ", expected: " + expressionType); |
| 707 } |
| 708 } |
| 709 |
| 710 // Check that dependencies correspond to "calculate" method arguments. |
| 711 Type[] methodParamTypes = calculateMethod.getGenericParameterTypes(); |
| 712 if (methodParamTypes.length != dependencyMethods.size()) { |
| 713 throw new IllegalArgumentException("Wrong number of agruments in calculate
method " + |
| 714 calculateMethod); |
| 715 } |
| 716 // We depend on methods being ordered in Java reflection. |
| 717 for (int i = 0; i < methodParamTypes.length; i++) { |
| 718 Method depMethod = dependencyMethods.get(i); |
| 719 try { |
| 720 if (depMethod.getParameterTypes().length != 0) { |
| 721 throw new IllegalArgumentException("Dependency method should not have
arguments"); |
| 722 } |
| 723 Type depType = depMethod.getGenericReturnType(); |
| 724 if (depType instanceof ParameterizedType == false) { |
| 725 throw new IllegalArgumentException("Dependency has wrong return type:
" + depType); |
| 726 } |
| 727 ParameterizedType depParameterizedType = (ParameterizedType) depType; |
| 728 if (depParameterizedType.getRawType() != ValueSource.class) { |
| 729 throw new IllegalArgumentException("Dependency has wrong return type:
" + depType); |
| 730 } |
| 731 // Method is typically in anonymous class. Making it accessible is requi
red. |
| 732 depMethod.setAccessible(true); |
| 733 } catch (IllegalArgumentException e) { |
| 734 throw new IllegalArgumentException("Failed to process method " + depMeth
od, e); |
| 735 } |
| 736 } |
| 737 |
| 738 // Create implementation that will call methods via reflection. |
| 739 return new Gettable<Optional<? extends RES>>() { |
| 740 @Override |
| 741 public Optional<? extends RES> getValue() { |
| 742 Object[] params = new Object[dependencyMethods.size()]; |
| 743 Set<Message> errors = null; |
| 744 for (int i = 0; i < params.length; i++) { |
| 745 Object sourceObject; |
| 746 try { |
| 747 sourceObject = dependencyMethods.get(i).invoke(expression); |
| 748 } catch (IllegalAccessException e) { |
| 749 throw new RuntimeException(e); |
| 750 } catch (InvocationTargetException e) { |
| 751 throw new RuntimeException(e); |
| 752 } |
| 753 ValueSource<? extends Optional<?>> source = |
| 754 (ValueSource<? extends Optional<?>>) sourceObject; |
| 755 Optional<?> optionalValue = source.getValue(); |
| 756 if (optionalValue.isNormal()) { |
| 757 params[i] = optionalValue.getNormal(); |
| 758 } else { |
| 759 if (errors == null) { |
| 760 errors = new LinkedHashSet<Message>(0); |
| 761 } |
| 762 errors.addAll(optionalValue.errorMessages()); |
| 763 } |
| 764 } |
| 765 if (errors == null) { |
| 766 Object result; |
| 767 try { |
| 768 result = calculateMethod.invoke(expression, params); |
| 769 } catch (IllegalAccessException e) { |
| 770 throw new RuntimeException(e); |
| 771 } catch (InvocationTargetException e) { |
| 772 throw new RuntimeException(e); |
| 773 } |
| 774 return returnValueHandler.castResult(result); |
| 775 } else { |
| 776 return createErrorOptional(errors); |
| 777 } |
| 535 } | 778 } |
| 536 }; | 779 }; |
| 537 return handleErrorsAddNew(wrapper, optionalSources); | |
| 538 } | |
| 539 | |
| 540 /** | |
| 541 * Implements the basic contract of {@link NormalExpression}. Wraps it as {@li
nk Gettable} and | |
| 542 * keeps all its optional sources that are checked before each calculation. | |
| 543 * The expression may rely on all optionalSources being of normal values, but
it is allowed to | |
| 544 * return error value itself. | |
| 545 */ | |
| 546 public static <RES> Gettable<Optional<RES>> handleErrorsAddNew( | |
| 547 final NormalExpression<Optional<RES>> expression, | |
| 548 final ValueSource<? extends Optional<?>> ... optionalSources) { | |
| 549 return new Gettable<Optional<RES>>() { | |
| 550 public Optional<RES> getValue() { | |
| 551 boolean hasErrors = false; | |
| 552 for (ValueSource<? extends Optional<?>> source : optionalSources) { | |
| 553 if (!source.getValue().isNormal()) { | |
| 554 hasErrors = true; | |
| 555 break; | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 if (hasErrors) { | |
| 560 Set<Message> errors = new LinkedHashSet<Message>(0); | |
| 561 for (ValueSource<? extends Optional<?>> source : optionalSources) { | |
| 562 if (!source.getValue().isNormal()) { | |
| 563 errors.addAll(source.getValue().errorMessages()); | |
| 564 } | |
| 565 } | |
| 566 return createErrorOptional(errors); | |
| 567 } else { | |
| 568 return expression.calculate(); | |
| 569 } | |
| 570 } | |
| 571 }; | |
| 572 } | 780 } |
| 573 | 781 |
| 574 public static ValueSource<? extends Optional<?>>[] dependencies( | 782 public static ValueSource<? extends Optional<?>>[] dependencies( |
| 575 ValueSource<? extends Optional<?>>... sources) { | 783 ValueSource<? extends Optional<?>>... sources) { |
| 576 return sources; | 784 return sources; |
| 577 } | 785 } |
| 578 | 786 |
| 579 | 787 |
| 580 /* | 788 /* |
| 581 * Part 3. Various utils. | 789 * Part 3. Various utils. |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 864 Optional<? extends T> control = expression.getValue(); | 1072 Optional<? extends T> control = expression.getValue(); |
| 865 if (control.isNormal()) { | 1073 if (control.isNormal()) { |
| 866 T tag = control.getNormal(); | 1074 T tag = control.getNormal(); |
| 867 newScope = getScopeForTag(tag); | 1075 newScope = getScopeForTag(tag); |
| 868 } else { | 1076 } else { |
| 869 newScope = null; | 1077 newScope = null; |
| 870 } | 1078 } |
| 871 setCurrentScope(newScope); | 1079 setCurrentScope(newScope); |
| 872 } | 1080 } |
| 873 | 1081 |
| 874 public <P> ValueSource<? extends Optional<P>> createOptionalMerge( | 1082 public <P> ValueSource<? extends Optional<? extends P>> createOptionalMerge( |
| 875 ValueSource<? extends Optional<P>>... sources) { | 1083 ValueSource<? extends Optional<? extends P>>... sources) { |
| 876 | 1084 |
| 877 final Map<T, ValueSource<? extends Optional<P>>> map = sortSources(Arrays.
asList(sources)); | 1085 final Map<T, ValueSource<? extends Optional<? extends P>>> map = |
| 1086 sortSources(Arrays.asList(sources)); |
| 878 | 1087 |
| 879 ValueProcessor<? extends Optional<P>> result = new ValueProcessor<Optional
<P>>() { | 1088 ValueProcessor<? extends Optional<? extends P>> result = |
| 1089 new ValueProcessor<Optional<? extends P>>() { |
| 880 public void update(Updater updater) { | 1090 public void update(Updater updater) { |
| 881 setCurrentValue(calculate()); | 1091 setCurrentValue(calculate()); |
| 882 updater.reportChanged(this); | 1092 updater.reportChanged(this); |
| 883 } | 1093 } |
| 884 | 1094 |
| 885 private Optional<P> calculate() { | 1095 private Optional<? extends P> calculate() { |
| 886 Optional<? extends T> control = sourceForMerge.getValue(); | 1096 Optional<? extends T> control = sourceForMerge.getValue(); |
| 887 if (control.isNormal()) { | 1097 if (control.isNormal()) { |
| 888 ValueSource<? extends Optional<P>> oneSource = map.get(control.getNo
rmal()); | 1098 ValueSource<? extends Optional<? extends P>> oneSource = map.get(con
trol.getNormal()); |
| 889 return oneSource.getValue(); | 1099 return oneSource.getValue(); |
| 890 } else { | 1100 } else { |
| 891 return createErrorOptional(control.errorMessages()); | 1101 return createErrorOptional(control.errorMessages()); |
| 892 } | 1102 } |
| 893 } | 1103 } |
| 894 }; | 1104 }; |
| 895 ScopeImpl outerScope = getOuterScope(); | 1105 ScopeImpl outerScope = getOuterScope(); |
| 896 Updater updater = outerScope.getUpdater(); | 1106 Updater updater = outerScope.getUpdater(); |
| 897 updater.addConsumer(outerScope, result); | 1107 updater.addConsumer(outerScope, result); |
| 898 updater.addDependency(result, getSourceForMerge()); | 1108 updater.addDependency(result, getSourceForMerge()); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 Updater getUpdater() { | 1155 Updater getUpdater() { |
| 946 return updater; | 1156 return updater; |
| 947 } | 1157 } |
| 948 | 1158 |
| 949 ScopeImpl(SwitcherBaseImpl<?> switcher, ScopeEnabler scopeEnabler, Updater u
pdater) { | 1159 ScopeImpl(SwitcherBaseImpl<?> switcher, ScopeEnabler scopeEnabler, Updater u
pdater) { |
| 950 this.switcher = switcher; | 1160 this.switcher = switcher; |
| 951 this.scopeEnabler = scopeEnabler; | 1161 this.scopeEnabler = scopeEnabler; |
| 952 this.updater = updater; | 1162 this.updater = updater; |
| 953 } | 1163 } |
| 954 | 1164 |
| 955 public <P> OptionalSwitcher<P> addOptionalSwitch(Gettable<? extends Optional
<P>> expression) { | 1165 public <P> OptionalSwitcher<P> addOptionalSwitch( |
| 1166 Gettable<? extends Optional<? extends P>> expression) { |
| 956 OptionalSwitcherImpl<P> switcher = new OptionalSwitcherImpl<P>(this, expre
ssion); | 1167 OptionalSwitcherImpl<P> switcher = new OptionalSwitcherImpl<P>(this, expre
ssion); |
| 957 updater.addConsumer(this, switcher.getValueConsumer()); | 1168 updater.addConsumer(this, switcher.getValueConsumer()); |
| 958 updater.addSource(this, switcher.getSourceForMerge()); | 1169 updater.addSource(this, switcher.getSourceForMerge()); |
| 959 updater.addDependency(switcher.getValueConsumer(), switcher.getSourceForMe
rge()); | 1170 updater.addDependency(switcher.getValueConsumer(), switcher.getSourceForMe
rge()); |
| 960 return switcher; | 1171 return switcher; |
| 961 } | 1172 } |
| 962 | 1173 |
| 963 public <P> Switcher<P> addSwitch(Gettable<P> expression) { | 1174 public <P> Switcher<P> addSwitch(Gettable<P> expression) { |
| 964 SwitcherImpl<P> switcher = new SwitcherImpl<P>(this, expression); | 1175 SwitcherImpl<P> switcher = new SwitcherImpl<P>(this, expression); |
| 965 updater.addConsumer(this, switcher.getValueConsumer()); | 1176 updater.addConsumer(this, switcher.getValueConsumer()); |
| 966 updater.addSource(this, switcher.getSourceForMerge()); | 1177 updater.addSource(this, switcher.getSourceForMerge()); |
| 967 updater.addDependency(switcher.getValueConsumer(), switcher.getSourceForMe
rge()); | 1178 updater.addDependency(switcher.getValueConsumer(), switcher.getSourceForMe
rge()); |
| 968 return switcher; | 1179 return switcher; |
| 969 } | 1180 } |
| 970 | 1181 |
| 971 public Scope getOuterScope() { | 1182 public Scope getOuterScope() { |
| 972 if (switcher == null) { | 1183 if (switcher == null) { |
| 973 return null; | 1184 return null; |
| 974 } | 1185 } |
| 975 return switcher.getOuterScope(); | 1186 return switcher.getOuterScope(); |
| 976 } | 1187 } |
| 977 } | 1188 } |
| 978 } | 1189 } |
| OLD | NEW |