This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/master by this push:
     new f69448c1b3 CAUSEWAY-3686: refining VetReason reduce algorithm
f69448c1b3 is described below

commit f69448c1b3e7b4cc631cdcdaf0b5c0874ace72b1
Author: Andi Huber <[email protected]>
AuthorDate: Thu Feb 8 15:46:54 2024 +0100

    CAUSEWAY-3686: refining VetReason reduce algorithm
    
    - this should fix quite some ban-icons appearing, where we don't really
    want them
---
 .../causeway/core/metamodel/consent/Consent.java   | 80 +++++++++++++++++++---
 .../authorization/AuthorizationFacetAbstract.java  |  2 +-
 2 files changed, 71 insertions(+), 11 deletions(-)

diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/consent/Consent.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/consent/Consent.java
index cefaee11fa..391180a5b6 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/consent/Consent.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/consent/Consent.java
@@ -38,15 +38,46 @@ public interface Consent {
     @lombok.Value @Accessors(fluent=true)
     public static class VetoReason implements Serializable {
         private static final long serialVersionUID = 1L;
+        /**
+         * Introduced to help pick a winner when merging 2 {@link 
VetoReason}(s).
+         * <p>
+         * PROGRAMMING_MODEL always wins over SECURITY.
+         */
+        public enum VetoOriging {
+            /**
+             * Veto originates from security mechanism.
+             * <p>
+             * In other words: the user is not authorized to either view or 
change the feature.
+             */
+            SECURITY,
+            /**
+             * Veto originates from programming model, either implicit or 
explicit see {@link UiHint}.
+             */
+            PROGRAMMING_MODEL;
+            public boolean isSecurity() { return this==SECURITY; }
+            public boolean isProgrammingModel() { return 
this==PROGRAMMING_MODEL; }
+            /** reduce to max ordinal */
+            static VetoOriging reduceToMaxOrdinal(final VetoOriging a, final 
VetoOriging b) {
+                return b.ordinal()>a.ordinal() ? b : a;
+            }
+        }
         /**
          * Introduced to help decide whether or not to display a 'ban' icon
          * in the UI, with a tooltip showing the disabled reason.
          */
         public enum UiHint {
             /**
-             * When prototyping, icon rendering can be suppressed via config 
option.
+             * Reason is <b>implicit</b> by programming model,
+             * reason text is generic and rather of interest to the developer
+             * than the end-user.
+             * <p>
+             * Show only when prototyping. However, when prototyping, can be 
suppressed via config option.
              */
             NO_ICON_UNLESS_PROTOTYPING,
+            /**
+             * Reason is <b>explicit</b> either by programming model or 
authentication mechanism,
+             * reason text is designated to reach the end-user.
+             */
             SHOW_BAN_ICON;
             public boolean isNoIconUnlessPrototying() { return 
this==NO_ICON_UNLESS_PROTOTYPING; }
             public boolean isShowBanIcon() { return this==SHOW_BAN_ICON; }
@@ -55,28 +86,57 @@ public interface Consent {
                 return b.ordinal()>a.ordinal() ? b : a;
             }
         }
+        private final VetoOriging vetoOriging;
         private final UiHint uiHint;
         private final @NonNull String string;
-        public static VetoReason explicit(final String reason) {
+        private static VetoReason of(
+                final @NonNull VetoOriging vetoOriging,
+                final @NonNull UiHint uiHint,
+                final String reason) {
             _Assert.assertTrue(_Strings.isNotEmpty(reason));
-            return new VetoReason(UiHint.SHOW_BAN_ICON, reason);
+            return new VetoReason(vetoOriging, uiHint, reason);
+        }
+        public static VetoReason unauthorized(final String reason) {
+            return of(VetoOriging.SECURITY, UiHint.SHOW_BAN_ICON, reason);
+        }
+        public static VetoReason explicit(final String reason) {
+            return of(VetoOriging.PROGRAMMING_MODEL, UiHint.SHOW_BAN_ICON, 
reason);
         }
         private static VetoReason inferred(final String reason) {
-            _Assert.assertTrue(_Strings.isNotEmpty(reason));
-            return new VetoReason(UiHint.NO_ICON_UNLESS_PROTOTYPING, reason);
+            return of(VetoOriging.PROGRAMMING_MODEL, 
UiHint.NO_ICON_UNLESS_PROTOTYPING, reason);
         }
         public Optional<VetoReason> toOptional() {
             return Optional.of(this);
         }
+        /**
+         * {@code Pi}: origin=PROGRAMMING_MODEL, nature=implicit 
(NO_ICON_UNLESS_PROTOTYPING)<br>
+         * {@code Pe}: origin=PROGRAMMING_MODEL, nature=explicit 
(SHOW_BAN_ICON)<br>
+         * {@code S(e)}: origin=SECURITY, nature=explicit (SHOW_BAN_ICON)<br>
+         * <p>
+         * {@code Pi ৹ Pi := pick any or concat}<br>
+         * {@code Pe ৹ Pe := pick any or concat}<br>
+         * {@code S(e) ৹ S(e) := pick any or concat}<br>
+         * <br>
+         * {@code Pi ৹ Pe := Pe}<br>
+         * {@code Pi ৹ S(e) := Pi}<br>
+         * {@code Pe ৹ S(e) := Pi}<br>
+         * In other words: winner picking is driven by <i>origin</i> first and 
<i>nature</i> second.
+         */
         public VetoReason reduce(final VetoReason other) {
+            // arbitrarily shifting left by 4 so reserving some room for more 
UiHint enum values
+            final int thisScore = (this.vetoOriging.ordinal()<<4)  + 
this.uiHint.ordinal();
+            final int otherScore = (other.vetoOriging.ordinal()<<4)  + 
other.uiHint.ordinal();
+
             final List<String> mergedText = new ArrayList<>(2);
-            switch(_Ints.compare(this.uiHint.ordinal(), 
other.uiHint.ordinal())) {
-            case -1: mergedText.add(other.string); break;
-            case 0:  mergedText.add(this.string); 
mergedText.add(other.string); break;
-            case 1:  mergedText.add(this.string); break;
+            final List<UiHint> winnerUiHint = new ArrayList<>(1);
+            switch(_Ints.compare(thisScore, otherScore)) {
+            case -1: winnerUiHint.add(other.uiHint); 
mergedText.add(other.string); break;
+            case 0:  winnerUiHint.add(this.uiHint); 
mergedText.add(this.string); mergedText.add(other.string); break;
+            case 1:  winnerUiHint.add(this.uiHint); 
mergedText.add(this.string); break;
             }
             return new VetoReason(
-                    UiHint.reduceToMaxOrdinal(this.uiHint, other.uiHint),
+                    VetoOriging.reduceToMaxOrdinal(this.vetoOriging, 
other.vetoOriging),
+                    winnerUiHint.get(0),
                     mergedText.stream().collect(Collectors.joining("; ")));
         }
         // -- PREDEFINED REASONS
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
index 066001442a..b9c1ed64ab 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
@@ -87,7 +87,7 @@ implements AuthorizationFacet {
             log.debug("disables[{}] -> {}", ic.getIdentifier(), disables);
         }
 
-        return Optional.ofNullable(disables).map(VetoReason::explicit);
+        return Optional.ofNullable(disables).map(VetoReason::unauthorized);
     }
 
 }

Reply via email to