You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/02/07 15:55:36 UTC

[isis] branch ISIS-2502-ex.recog updated: ISIS-2502: registers the ExceptionRecognizerForOtherDataAccessProblem

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

ahuber pushed a commit to branch ISIS-2502-ex.recog
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/ISIS-2502-ex.recog by this push:
     new 83617d4  ISIS-2502: registers the ExceptionRecognizerForOtherDataAccessProblem
83617d4 is described below

commit 83617d4accdb99534d053022fa05818d34448e0a
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Feb 7 16:55:20 2021 +0100

    ISIS-2502: registers the ExceptionRecognizerForOtherDataAccessProblem
    
    also makes the ExceptionRecognizer construction a bit more flexible
---
 .../exceprecog/ExceptionRecognizerAbstract.java    | 34 +++++++++++++---------
 .../exceprecog/ExceptionRecognizerForType.java     | 17 +++++------
 .../exceprecog/ExceptionRecognizerForTypeTest.java |  6 ++--
 .../IsisModuleCoreRuntimeServices.java             |  2 ++
 .../ExceptionRecognizerForDataAccessException.java | 10 +++----
 ...ceptionRecognizerForOtherDataAccessProblem.java | 28 +++++++++++++++++-
 .../wicket/ui/panels/FormExecutorDefault.java      | 30 ++++++++-----------
 7 files changed, 78 insertions(+), 49 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerAbstract.java
index 4651b88..3850c42 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerAbstract.java
@@ -22,7 +22,6 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
 
 import javax.inject.Inject;
 
@@ -66,32 +65,42 @@ public abstract class ExceptionRecognizerAbstract implements ExceptionRecognizer
      * Convenience for subclass implementations that always prefixes the exception message
      * with the supplied text
      */
-    protected static UnaryOperator<String> prefix(final String prefix) {
-        return $->prefix + ": " + $;
+    protected static Function<Throwable, String> prefix(final String prefix) {
+        return rootCause->prefix + ": " + rootCause.getMessage();
     }
 
     private final Category category;
     private final Predicate<Throwable> predicate;
-    private final Function<String,String> messageParser;
+    private final Function<Throwable, String> rootCauseMessageFormatter;
 
     protected boolean logRecognizedExceptions;
 
-    public ExceptionRecognizerAbstract(final Category category, Predicate<Throwable> predicate, final Function<String,String> messageParser) {
+    public ExceptionRecognizerAbstract(
+            final Category category, 
+            final Predicate<Throwable> predicate, 
+            final Function<Throwable, String> rootCauseMessageFormatter) {
         Objects.requireNonNull(predicate);
         this.category = category;
         this.predicate = predicate;
-        this.messageParser = messageParser != null ? messageParser : Function.identity();
+        this.rootCauseMessageFormatter = rootCauseMessageFormatter != null 
+                ? rootCauseMessageFormatter 
+                : Throwable::getMessage;
     }
 
-    public ExceptionRecognizerAbstract(Predicate<Throwable> predicate, final Function<String,String> messageParser) {
-        this(Category.OTHER, predicate, messageParser);
+    public ExceptionRecognizerAbstract(
+            final Predicate<Throwable> predicate, 
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        this(Category.OTHER, predicate, rootCauseMessageFormatter);
     }
 
-    public ExceptionRecognizerAbstract(Category category, Predicate<Throwable> predicate) {
+    public ExceptionRecognizerAbstract(
+            final Category category, 
+            final Predicate<Throwable> predicate) {
         this(category, predicate, null);
     }
 
-    public ExceptionRecognizerAbstract(Predicate<Throwable> predicate) {
+    public ExceptionRecognizerAbstract(
+            final Predicate<Throwable> predicate) {
         this(Category.OTHER, predicate);
     }
 
@@ -114,9 +123,8 @@ public abstract class ExceptionRecognizerAbstract implements ExceptionRecognizer
                 }
             }
             final Throwable rootCause = _Exceptions.getRootCause(throwable);
-            final String rootCauseMessage = rootCause.getMessage();
-            final String parsedMessage = messageParser.apply(rootCauseMessage);
-            return parsedMessage;
+            final String formattedMessage = rootCauseMessageFormatter.apply(rootCause);
+            return formattedMessage;
         })
         .filter(_NullSafe::isPresent)
         .findFirst();
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
index 5edbd5e..5f96545 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
@@ -20,7 +20,6 @@ package org.apache.isis.applib.services.exceprecog;
 
 import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
 
 import static org.apache.isis.commons.internal.exceptions._Exceptions.containsAnyOfTheseMessages;
 import static org.apache.isis.commons.internal.exceptions._Exceptions.getCausalChain;
@@ -95,15 +94,15 @@ public class ExceptionRecognizerForType extends ExceptionRecognizerAbstract {
     public ExceptionRecognizerForType(
             final Category category,
             final Class<? extends Exception> exceptionType,
-            final UnaryOperator<String> messageParser) {
-        this(category, ofType(exceptionType), messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        this(category, ofType(exceptionType), rootCauseMessageFormatter);
     }
 
     public ExceptionRecognizerForType(
             final Category category,
             final Predicate<Throwable> predicate,
-            final UnaryOperator<String> messageParser) {
-        super(category, predicate, messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        super(category, predicate, rootCauseMessageFormatter);
     }
 
     public ExceptionRecognizerForType(
@@ -114,14 +113,14 @@ public class ExceptionRecognizerForType extends ExceptionRecognizerAbstract {
 
     public ExceptionRecognizerForType(
             final Class<? extends Exception> exceptionType,
-            final UnaryOperator<String> messageParser) {
-        this(Category.OTHER, exceptionType, messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        this(Category.OTHER, exceptionType, rootCauseMessageFormatter);
     }
 
     public ExceptionRecognizerForType(
             final Predicate<Throwable> predicate,
-            final UnaryOperator<String> messageParser) {
-        this(Category.OTHER, predicate, messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        this(Category.OTHER, predicate, rootCauseMessageFormatter);
     }
 
     public ExceptionRecognizerForType(Class<? extends Exception> exceptionType) {
diff --git a/api/applib/src/test/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForTypeTest.java b/api/applib/src/test/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForTypeTest.java
index 23625c1..7d0016c 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForTypeTest.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForTypeTest.java
@@ -20,7 +20,7 @@
 package org.apache.isis.applib.services.exceprecog;
 
 import java.util.Optional;
-import java.util.function.UnaryOperator;
+import java.util.function.Function;
 
 import org.junit.Test;
 
@@ -45,7 +45,7 @@ public class ExceptionRecognizerForTypeTest {
         }
     }
 
-    private UnaryOperator<String> prepend = $ -> "pre: " + $;
+    private Function<Throwable, String> rootCauseMessageFormatter = ex -> "pre: " + ex.getMessage();
 
     @Test
     public void whenRecognized() {
@@ -61,7 +61,7 @@ public class ExceptionRecognizerForTypeTest {
 
     @Test
     public void whenRecognizedWithMessageParser() {
-        ersForType = new ExceptionRecognizerForType(FooException.class, prepend);
+        ersForType = new ExceptionRecognizerForType(FooException.class, rootCauseMessageFormatter);
         assertThat(ersForType.recognize(new FooException()).get().getReason(), is("pre: foo"));
     }
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
index a0c5385..7fb081a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
@@ -53,6 +53,7 @@ import org.apache.isis.core.runtimeservices.queryresultscache.QueryResultsCacheD
 import org.apache.isis.core.runtimeservices.recognizer.ExceptionRecognizerServiceDefault;
 import org.apache.isis.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForDataAlreadyExists;
 import org.apache.isis.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForObjectNotFound;
+import org.apache.isis.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForOtherDataAccessProblem;
 import org.apache.isis.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForRelatedDataExists;
 import org.apache.isis.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForUnableToSaveData;
 import org.apache.isis.core.runtimeservices.repository.RepositoryServiceDefault;
@@ -124,6 +125,7 @@ import org.apache.isis.core.runtimeservices.xmlsnapshot.XmlSnapshotServiceDefaul
         ExceptionRecognizerForObjectNotFound.class,
         ExceptionRecognizerForRelatedDataExists.class,
         ExceptionRecognizerForUnableToSaveData.class,
+        ExceptionRecognizerForOtherDataAccessProblem.class,
 
 })
 public class IsisModuleCoreRuntimeServices {
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
index 39494c9..f86c298 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
@@ -18,8 +18,8 @@
  */
 package org.apache.isis.core.runtimeservices.recognizer.dae;
 
+import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
 
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
 import org.apache.isis.core.config.IsisConfiguration;
@@ -34,8 +34,8 @@ extends ExceptionRecognizerForType {
             final IsisConfiguration isisConfiguration,
             final Category category,
             final Predicate<Throwable> predicate,
-            final UnaryOperator<String> messageParser) {
-        super(category, predicate, messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        super(category, predicate, rootCauseMessageFormatter);
         
         super.setDisabled(
                 isisConfiguration.getCore().getRuntimeServices()
@@ -46,8 +46,8 @@ extends ExceptionRecognizerForType {
             final IsisConfiguration isisConfiguration,
             final Category category,
             final Class<? extends Exception> exceptionType,
-            final UnaryOperator<String> messageParser) {
-        this(isisConfiguration, category, ofType(exceptionType), messageParser);
+            final Function<Throwable, String> rootCauseMessageFormatter) {
+        this(isisConfiguration, category, ofType(exceptionType), rootCauseMessageFormatter);
     }
 
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
index f781bc8..f6fd0d5 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.core.runtimeservices.recognizer.dae.impl;
 
+import java.util.stream.Collectors;
+
 import javax.inject.Inject;
 import javax.inject.Named;
 
@@ -27,9 +29,12 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
 
+import lombok.val;
+
 /**
  * Recognizes exceptions of type {@link DataAccessException} if no one else does (fallback). 
  *  
@@ -49,7 +54,28 @@ extends ExceptionRecognizerForDataAccessException {
         super(conf,
                 Category.OTHER,
                 ofType(org.springframework.dao.DataAccessException.class),
-                prefix("An unrecognized data access problem has occurred: ")); 
+                rootCause->toMessage(rootCause)); 
     }
 
+    private static String toMessage(Throwable rootCause) {
+        
+        val causalInfo = _Exceptions.getCausalChain(rootCause)
+        .stream()
+        .skip(1L)
+        .map(ex->String.format("%s: %s", ex.getClass().getSimpleName(), ex.getMessage()))
+        .collect(Collectors.joining(", "));
+        
+        return causalInfo.isEmpty()
+                ? String.format(
+                        "An unrecognized data access problem has occurred: %s\ncaused by %s",
+                        rootCause.getMessage(),
+                        rootCause.getClass().getSimpleName()
+                        )
+                : String.format(
+                        "An unrecognized data access problem has occurred: %s\ncausal chain: %s",
+                        rootCause.getMessage(),
+                        causalInfo);
+    }
+    
+    
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index d1f7a79..cddadad 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -41,7 +41,6 @@ import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.core.interaction.session.InteractionFactory;
@@ -90,7 +89,8 @@ implements FormExecutor {
      * @param feedbackFormIfAny
      * @param withinPrompt
      *
-     * @return <tt>false</tt> - if invalid args; if concurrency exception; <tt>true</tt> if redirecting to new page, or repainting all components
+     * @return <tt>false</tt> - if invalid args; 
+     * <tt>true</tt> if redirecting to new page, or repainting all components
      */
     @Override
     public boolean executeAndProcessResults(
@@ -119,6 +119,7 @@ implements FormExecutor {
                 return false;
             }
 
+            val commonContext = targetEntityModel.getCommonContext();
 
             //
             // the following line will (attempt to) invoke the action, and will in turn either:
@@ -128,30 +129,23 @@ implements FormExecutor {
             // 2. return a null result (from a successful action returning void)
             //
             // 3. throws a RuntimeException, either:
-            //    a) as result of application throwing RecoverableException/ApplicationException (DN xactn still intact)
-            //    b) as result of DB exception, eg uniqueness constraint violation (DN xactn marked to abort)
-            //    Either way, as a side-effect the Isis transaction will be set to MUST_ABORT (IsisTransactionManager does this)
+            //    a) as result of application throwing RecoverableException (DN transaction still intact)
+            //    b) as result of DB exception, eg uniqueness constraint violation (DN transaction marked to abort)
             //
             // (The DB exception might actually be thrown by the flush() that follows.
             //
             val resultAdapter = obtainResultAdapter();
             // flush any queued changes; any concurrency or violation exceptions will actually be thrown here
-            {
-                val commonContext = targetEntityModel.getCommonContext();
-                commonContext.getInteractionTracker().currentInteractionSession()
-                .ifPresent(interaction->{
-                    commonContext.lookupServiceElseFail(TransactionService.class)
-                    .flushTransaction();
-                });
-            }
+            if(commonContext.getInteractionTracker().isInInteractionSession()) {
+                commonContext.getTransactionService().flushTransaction();
 
-            // update target, since version updated (concurrency checks)
-            targetAdapter = targetEntityModel.getManagedObject();
-            if(!EntityUtil.isDestroyed(targetAdapter)) {
-                targetEntityModel.resetPropertyModels();
+                // update target, since version updated
+                targetAdapter = targetEntityModel.getManagedObject();
+                if(!EntityUtil.isDestroyed(targetAdapter)) {
+                    targetEntityModel.resetPropertyModels();
+                }
             }
 
-
             // hook to close prompt etc.
             onExecuteAndProcessResults(targetIfAny);