]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4925 Fix an issue with unexpected exception thrown by proxified objects
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 7 Feb 2014 11:46:52 +0000 (12:46 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 7 Feb 2014 11:50:15 +0000 (12:50 +0100)
sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingConnectionHandler.java
sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingPreparedStatementHandler.java
sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingStatementHandler.java
sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/persistence/profiling/PersistenceProfilingTest.java

diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java
new file mode 100644 (file)
index 0000000..0ac7960
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.core.persistence.profiling;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class InvocationUtils {
+
+  private InvocationUtils() {
+    // Only private stuff
+  }
+
+  static Object invokeQuietly(Object target, Method method, Object[] params) throws Throwable {
+    Object result = null;
+    try {
+      result = method.invoke(target, params);
+    } catch(InvocationTargetException invocationException) {
+      for (Class<?> exceptionClass: method.getExceptionTypes()) {
+        if (exceptionClass.isInstance(invocationException.getCause())) {
+          throw invocationException.getCause();
+        }
+        throw new IllegalStateException(invocationException.getCause());
+      }
+    }
+    return result;
+  }
+}
index 1a8c86eed332ccf4a2b15d67396dbd766b30fe87..aa16400b62979420676b1d118b50b2ed636fc851 100644 (file)
@@ -36,7 +36,7 @@ class ProfilingConnectionHandler implements InvocationHandler {
 
   @Override
   public Object invoke(Object target, Method method, Object[] args) throws Throwable {
-    Object result = method.invoke(connection, args);
+    Object result = InvocationUtils.invokeQuietly(connection, method, args);
     if ("prepareStatement".equals(method.getName())) {
       PreparedStatement statement = (PreparedStatement) result;
       String sql = (String) args[0];
index 8550e7bfe197059da3e91b8a8ca6dd4482a63565..f3fa082b94e5b2b51dc10827df65d0ec3c19ac92 100644 (file)
@@ -19,8 +19,8 @@
  */
 package org.sonar.core.persistence.profiling;
 
-import org.apache.commons.lang.StringUtils;
 import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
 import org.sonar.core.profiling.StopWatch;
 
 import java.lang.reflect.InvocationHandler;
@@ -52,21 +52,25 @@ class ProfilingPreparedStatementHandler implements InvocationHandler {
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     if (method.getName().startsWith("execute")) {
       StopWatch watch = PROFILING.start();
-      Object result = method.invoke(statement, args);
-      StringBuilder sqlBuilder = new StringBuilder().append(sql);
-      if (!arguments.isEmpty()) {
-        sqlBuilder.append(" - parameters are: ");
-        for (Object arg: arguments) {
-          sqlBuilder.append(PARAM_PREFIX).append(arg).append(PARAM_SUFFIX).append(PARAM_SEPARATOR);
+      Object result = null;
+      try {
+        result = InvocationUtils.invokeQuietly(statement, method, args);
+      } finally {
+        StringBuilder sqlBuilder = new StringBuilder().append(sql);
+        if (!arguments.isEmpty()) {
+          sqlBuilder.append(" - parameters are: ");
+          for (Object arg: arguments) {
+            sqlBuilder.append(PARAM_PREFIX).append(arg).append(PARAM_SUFFIX).append(PARAM_SEPARATOR);
+          }
         }
+        PROFILING.stop(watch, StringUtils.removeEnd(sqlBuilder.toString(), PARAM_SEPARATOR));
       }
-      PROFILING.stop(watch, StringUtils.removeEnd(sqlBuilder.toString(), PARAM_SEPARATOR));
       return result;
     } else if (method.getName().startsWith("set") && args.length > 1) {
       arguments.set((Integer) args[0] - 1, args[1]);
-      return method.invoke(statement, args);
+      return InvocationUtils.invokeQuietly(statement, method, args);
     } else {
-      return method.invoke(statement, args);
+      return InvocationUtils.invokeQuietly(statement, method, args);
     }
   }
 
index 89d91c0db816820a39e8a862ca0fa46c0eec8086..152f26661fec5e8abd982fe61ecfe3c49b1bf4c8 100644 (file)
@@ -39,11 +39,15 @@ class ProfilingStatementHandler implements InvocationHandler {
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     if (method.getName().startsWith("execute")) {
       StopWatch watch = PROFILING.start();
-      Object result = method.invoke(statement, args);
-      PROFILING.stop(watch, (String) args[0]);
+      Object result = null;
+      try {
+        result = InvocationUtils.invokeQuietly(statement, method, args);
+      } finally {
+        PROFILING.stop(watch, (String) args[0]);
+      }
       return result;
     } else {
-      return method.invoke(statement, args);
+      return InvocationUtils.invokeQuietly(statement, method, args);
     }
   }
 }
diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java
new file mode 100644 (file)
index 0000000..53844aa
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.core.persistence.profiling;
+
+import org.fest.assertions.Fail;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class InvocationUtilsTest {
+
+  @Test
+  public void should_return_result() throws Throwable {
+    String toString = "toString";
+    Object target = mock(Object.class);
+    when(target.toString()).thenReturn(toString);
+
+    assertThat(InvocationUtils.invokeQuietly(target, Object.class.getMethod("toString"), new Object[0])).isEqualTo(toString);
+  }
+
+  @Test
+  public void should_throw_declared_exception() throws Throwable {
+    Connection target = mock(Connection.class);
+    String failSql = "any sql";
+    when(target.prepareStatement(failSql)).thenThrow(new SQLException("Expected"));
+
+    try {
+      InvocationUtils.invokeQuietly(target, Connection.class.getMethod("prepareStatement", String.class), new Object[] { failSql });
+      Fail.fail();
+    } catch (Throwable t) {
+      assertThat(t).isInstanceOf(SQLException.class);
+    }
+  }
+
+  @Test
+  public void should_wrap_undeclared_exception() throws Throwable {
+    Connection target = mock(Connection.class);
+    String failSql = "any sql";
+    when(target.prepareStatement(failSql)).thenThrow(new SQLException("Expected"));
+
+    try {
+      InvocationUtils.invokeQuietly(target, Object.class.getMethod("wait"), new Object[0]);
+      Fail.fail();
+    } catch (Throwable t) {
+      assertThat(t).isInstanceOf(IllegalStateException.class);
+    }
+  }
+}
index 9faec0790e3295a1e5926e7121a3b96342b247f9..1ad3213e860dd9fefa8f95b0d2865ffaba1f3339 100644 (file)
@@ -31,11 +31,7 @@ import org.sonar.api.config.Settings;
 import org.sonar.core.profiling.Profiling;
 
 import java.io.ByteArrayInputStream;
-import java.sql.Connection;
-import java.sql.Date;
-import java.sql.PreparedStatement;
-import java.sql.Statement;
-import java.sql.Timestamp;
+import java.sql.*;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;