From b49e4c9f28c3fd2c89930c0cd7af8836d75ec2b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20Sch=C3=A4rtl?= <andreas@schaertl.me>
Date: Thu, 21 May 2020 14:44:36 +0200
Subject: [PATCH] uloapi: GraphDB: improve error handling

---
 .../info/mathhub/uloapi/query/GraphDB.java    | 50 +++++++++++++++++--
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/GraphDB.java b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/GraphDB.java
index 0214feb..055c86d 100644
--- a/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/GraphDB.java
+++ b/experimental/uloapi/src/main/java/info/mathhub/uloapi/query/GraphDB.java
@@ -36,6 +36,16 @@ public class GraphDB {
         T op(RepositoryManager manager, Repository repository, RepositoryConnection connection);
     }
 
+    /**
+     * Functional interface that defines a function that takes nothing, does something
+     * and returns nothing.
+     *
+     * Functional programmers hate this.
+     */
+    private interface Procedure {
+        void apply() throws Exception;
+    }
+
     /**
      * Run an operation on a remote repository.
      *
@@ -52,6 +62,9 @@ public class GraphDB {
         Repository repository = null;
         RepositoryConnection connection = null;
 
+        Exception err = null;
+        T result = null;
+
         try {
             manager = new RemoteRepositoryManager(serverUrl);
             manager.init();
@@ -61,20 +74,49 @@ public class GraphDB {
             }
 
             connection = repository.getConnection();
-            return op.op(manager, repository, connection);
+            result = op.op(manager, repository, connection);
+        } catch (Exception e) {
+            err = e;
         } finally {
             if (connection != null) {
-                connection.close();
+                err = chain(err, connection::close);
             }
 
             if (repository != null) {
-                repository.shutDown();
+                err = chain(err, repository::shutDown);
             }
 
             if (manager != null) {
-                manager.shutDown();
+                err = chain(err, manager::shutDown);
+            }
+        }
+
+        if (err != null) {
+            throw new OperationException("execute failed", err);
+        }
+
+        return result;
+    }
+
+    /**
+     * Execute proc and return {@code e} if not {@code null}, the exception
+     * caused by {@code proc} or {@code null}.
+     * @return If {@code e} is not {@code null}, always return {@code e}.
+     * Otherwise, if {@code proc} caused an exception, return that exception or
+     * return {@code null} if {@code proc} did not cause an exception.
+     */
+    private static Exception chain(Exception e, Procedure proc) {
+        Exception ret = e;
+
+        try {
+            proc.apply();
+        } catch (Exception ne) {
+            if (ret == null) {
+                ret = ne;
             }
         }
+
+        return ret;
     }
 }
 
-- 
GitLab