From 8ce6c7ee3ef5f65424aebd788ae2f96af1d68d2d Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Tue, 12 Jul 2011 11:42:34 +0000
Subject: [PATCH] [LMS-2368] introduced AOP advisor for translation of
 TransactionExceptions on server level

SVN: 22086
---
 ...entServiceExceptionTranslatingAdvisor.java | 18 +---
 .../ServerExceptionTranslatingAdvisor.java    | 85 +++++++++++++++++++
 .../source/java/genericApplicationContext.xml |  6 ++
 3 files changed, 92 insertions(+), 17 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/ClientServiceExceptionTranslatingAdvisor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/ClientServiceExceptionTranslatingAdvisor.java
index a154f89a5d8..828b1e393d2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/ClientServiceExceptionTranslatingAdvisor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/ClientServiceExceptionTranslatingAdvisor.java
@@ -23,9 +23,7 @@ import org.springframework.aop.MethodMatcher;
 import org.springframework.aop.Pointcut;
 import org.springframework.aop.support.DefaultPointcutAdvisor;
 import org.springframework.aop.support.RootClassFilter;
-import org.springframework.transaction.TransactionSystemException;
 
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.client.web.client.IClientService;
 import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailureExceptionTranslator;
 
@@ -67,26 +65,12 @@ public class ClientServiceExceptionTranslatingAdvisor extends DefaultPointcutAdv
         {
             try
             {
-                return proceedWithTransactionSystemExceptionTranslation(invocation);
+                return invocation.proceed();
             } catch (ch.systemsx.cisd.common.exceptions.UserFailureException ex)
             {
                 throw UserFailureExceptionTranslator.translate(ex);
             }
         }
-
-        private Object proceedWithTransactionSystemExceptionTranslation(MethodInvocation invocation)
-                throws Throwable
-        {
-            try
-            {
-                return invocation.proceed();
-            } catch (TransactionSystemException e)
-            {
-                // Deferred trigger may throw an exception just before commit.
-                // Message in the exception is readable for the user.
-                throw new UserFailureException(e.getMostSpecificCause().getMessage());
-            }
-        }
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java
new file mode 100644
index 00000000000..870c819d29a
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.aop.ClassFilter;
+import org.springframework.aop.MethodMatcher;
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.aop.support.RootClassFilter;
+import org.springframework.core.NestedRuntimeException;
+import org.springframework.transaction.TransactionSystemException;
+import org.springframework.transaction.annotation.Transactional;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+
+/**
+ * Translates deeply nested exceptions thrown on server side e.g. by Spring (like
+ * {@link TransactionSystemException}) into {UserFailureException} with message taken from the root
+ * exception cause.
+ * <p>
+ * The most important reason why this advisor was introduced was to translate exceptions that happen
+ * just before commit/rollback of transactions, like {@link TransactionSystemException}. Such
+ * exceptions can't be handled inside the server methods because the commit/rollback is invoked
+ * outside the server class by Spring AOP (see {@link Transactional}). Without this advisor the
+ * translation would need to be done in all clients - web, command line, APIs.
+ * 
+ * @author Piotr Buczek
+ */
+public class ServerExceptionTranslatingAdvisor extends DefaultPointcutAdvisor
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public ServerExceptionTranslatingAdvisor()
+    {
+        super(new AllServerMethodsPointcut(), new UserFailureExceptionTranslatingInterceptor());
+    }
+
+    private static class AllServerMethodsPointcut implements Pointcut
+    {
+        public MethodMatcher getMethodMatcher()
+        {
+            return MethodMatcher.TRUE;
+        }
+
+        public ClassFilter getClassFilter()
+        {
+            return new RootClassFilter(IServer.class);
+        }
+    }
+
+    private static class UserFailureExceptionTranslatingInterceptor implements MethodInterceptor
+    {
+        public Object invoke(MethodInvocation invocation) throws Throwable
+        {
+            try
+            {
+                return invocation.proceed();
+            } catch (NestedRuntimeException e) // e.g. TransactionSystemException
+            {
+                // Deferred trigger may throw an exception just before commit.
+                // Message in the exception is readable for the user.
+                throw new UserFailureException(e.getMostSpecificCause().getMessage());
+            }
+        }
+    }
+
+}
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index 3558d0caa19..672df3f4730 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -113,6 +113,12 @@
      -->
     <bean id="html-escaping-advisor" class="ch.systemsx.cisd.openbis.generic.client.web.server.StringHtmlEscapingPointcutAdvisor" />
     
+    <!--
+        // Exception translation
+     -->
+    <bean id="client-service-exception-translating-advisor" class="ch.systemsx.cisd.openbis.generic.client.web.server.ClientServiceExceptionTranslatingAdvisor" />
+    <bean id="server-exception-translating-advisor" class="ch.systemsx.cisd.openbis.generic.server.ServerExceptionTranslatingAdvisor" />
+    
     <bean id="rpc-name-server" class="ch.systemsx.cisd.common.api.server.RpcServiceNameServer" />
     
     <!-- 
-- 
GitLab