]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4547 improve support of MessageException
authorSimon Brandhof <simon.brandhof@gmail.com>
Fri, 16 Aug 2013 15:46:06 +0000 (17:46 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Fri, 16 Aug 2013 15:46:06 +0000 (17:46 +0200)
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ProfileSensorTest.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/DatabaseCompatibility.java
sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
sonar-maven-plugin/src/main/java/org/sonar/maven/ExceptionHandling.java [new file with mode: 0644]
sonar-maven-plugin/src/main/java/org/sonar/maven/SonarMojo.java
sonar-maven-plugin/src/test/java/org/sonar/maven/ExceptionHandlingTest.java [new file with mode: 0644]
sonar-maven-plugin/src/test/java/org/sonar/runner/impl/RunnerException.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/utils/MessageException.java
sonar-plugin-api/src/test/java/org/sonar/api/utils/MessageExceptionTest.java
sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java

index 24fbaa07b453ef399e3963704d4b026470e600ee..cce7bab108797df3af7b0a12bd4af07fd29de1b1 100644 (file)
 package org.sonar.plugins.core.sensors;
 
 import org.junit.Test;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
 import org.sonar.api.batch.SensorContext;
 import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.profiles.RulesProfile;
 import org.sonar.api.test.IsMeasure;
 
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.*;
+
 public class ProfileSensorTest {
 
   @Test
index 26f0f425015775d49638b0e3e2c335af67965630..6fe7394e040f5377b0c69d774b9c48170a1da339 100644 (file)
@@ -59,21 +59,21 @@ public class DatabaseCompatibility implements BatchComponent {
       message.append(" / *****)\n\t- Server side: check the configuration at ");
       message.append(server.getURL());
       message.append("/system\n");
-      throw new MessageException(message.toString());
+      throw MessageException.of(message.toString());
     }
   }
 
   private void checkDatabaseStatus() {
     DatabaseVersion.Status status = version.getStatus();
     if (status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) {
-      throw new MessageException("Database relates to a more recent version of SonarQube. Please check your settings (JDBC settings, version of Maven plugin)");
+      throw MessageException.of("Database relates to a more recent version of SonarQube. Please check your settings (JDBC settings, version of Maven plugin)");
     }
     if (status == DatabaseVersion.Status.REQUIRES_UPGRADE) {
-      throw new MessageException("Database must be upgraded. Please browse " + server.getURL() + "/setup");
+      throw MessageException.of("Database must be upgraded. Please browse " + server.getURL() + "/setup");
     }
     if (status != DatabaseVersion.Status.UP_TO_DATE) {
       // Support other future values
-      throw new MessageException("Unknown database status: " + status);
+      throw MessageException.of("Unknown database status: " + status);
     }
   }
 
index 7d77355ef11c7534b810f4a49d548ca23cc6e014..539fc1e4529e440889c61767933045a730b050bf 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.batch.DecoratorContext;
 import org.sonar.api.batch.SonarIndex;
 import org.sonar.api.resources.Project;
 import org.sonar.api.resources.Resource;
+import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.SonarException;
 import org.sonar.batch.DecoratorsSelector;
 import org.sonar.batch.DefaultDecoratorContext;
@@ -80,6 +81,9 @@ public class DecoratorsExecutor implements BatchComponent {
       decorator.decorate(resource, context);
       eventBus.fireEvent(new DecoratorExecutionEvent(decorator, false));
 
+    } catch (MessageException e) {
+      throw e;
+
     } catch (Exception e) {
       // SONAR-2278 the resource should not be lost in exception stacktrace.
       throw new SonarException("Fail to decorate '" + resource + "'", e);
diff --git a/sonar-maven-plugin/src/main/java/org/sonar/maven/ExceptionHandling.java b/sonar-maven-plugin/src/main/java/org/sonar/maven/ExceptionHandling.java
new file mode 100644 (file)
index 0000000..2fcd44e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+
+class ExceptionHandling {
+
+  static RuntimeException handle(Exception e, Log log) throws MojoExecutionException {
+    Throwable source = e;
+    if (e.getClass().getName().equals("org.sonar.runner.impl.RunnerException") && e.getCause() != null) {
+      source = e.getCause();
+    }
+    log.error(source.getMessage());
+    throw new MojoExecutionException(source.getMessage(), source);
+  }
+
+  static RuntimeException handle(String message, Log log) throws MojoExecutionException {
+    return handle(new MojoExecutionException(message), log);
+  }
+}
index 14213720c231bddded940d5d510f4ced02c8cdf4..d62389c69700caa96fcc96c48b3a566e512385d9 100644 (file)
@@ -29,7 +29,6 @@ import org.apache.maven.execution.RuntimeInformation;
 import org.apache.maven.lifecycle.LifecycleExecutor;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectBuilder;
 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
@@ -127,23 +126,25 @@ public final class SonarMojo extends AbstractMojo {
    */
   RuntimeInformation runtimeInformation;
 
-  public void execute() throws MojoExecutionException, MojoFailureException {
+  @Override
+  public void execute() throws MojoExecutionException {
     ArtifactVersion mavenVersion = getMavenVersion();
     if (mavenVersion.getMajorVersion() == 2 && mavenVersion.getMinorVersion() < 2) {
-      throw new MojoExecutionException("Please use at least Maven 2.2.x to perform SonarQube analysis (current version is " + mavenVersion.toString() + ")");
+      ExceptionHandling.handle("Please use at least Maven 2.2.x to perform SonarQube analysis (current version is " + mavenVersion.toString() + ")", getLog());
     }
 
-    EmbeddedRunner runner = EmbeddedRunner.create()
+    try {
+      EmbeddedRunner runner = EmbeddedRunner.create()
         .setApp("Maven", mavenVersion.toString())
         .addProperties(session.getExecutionProperties())
         .addProperties(project.getModel().getProperties())
         // Add user properties (ie command line arguments -Dsonar.xxx=yyyy) in last position to override all other
         .addProperties(session.getUserProperties());
-    String encoding = getSourceEncoding(project);
-    if (encoding != null) {
-      runner.setProperty(ScanProperties.PROJECT_SOURCE_ENCODING, encoding);
-    }
-    runner
+      String encoding = getSourceEncoding(project);
+      if (encoding != null) {
+        runner.setProperty(ScanProperties.PROJECT_SOURCE_ENCODING, encoding);
+      }
+      runner
         .setProperty(ScanProperties.PROJECT_KEY, getSonarKey(project))
         .setProperty(RunnerProperties.WORK_DIR, getSonarWorkDir(project).getAbsolutePath())
         .setProperty(ScanProperties.PROJECT_BASEDIR, project.getBasedir().getAbsolutePath())
@@ -151,25 +152,28 @@ public final class SonarMojo extends AbstractMojo {
         .setProperty(ScanProperties.PROJECT_NAME, toString(project.getName()))
         .setProperty(ScanProperties.PROJECT_DESCRIPTION, toString(project.getDescription()))
         .setProperty(ScanProperties.PROJECT_SOURCE_DIRS, ".");
-    // Exclude log implementation to not conflict with Maven 3.1 logging impl
-    runner.mask("org.slf4j.LoggerFactory")
+      // Exclude log implementation to not conflict with Maven 3.1 logging impl
+      runner.mask("org.slf4j.LoggerFactory")
         // Include slf4j Logger that is exposed by some Sonar components
         .unmask("org.slf4j.Logger")
         .unmask("org.slf4j.ILoggerFactory")
-        // Exclude other slf4j classes
-        // .unmask("org.slf4j.impl.")
+          // Exclude other slf4j classes
+          // .unmask("org.slf4j.impl.")
         .mask("org.slf4j.")
-        // Exclude logback
+          // Exclude logback
         .mask("ch.qos.logback.")
         .mask("org.sonar.")
-        // Include everything else
+          // Include everything else
         .unmask("");
-    runner.addExtensions(session, getLog(), lifecycleExecutor, artifactFactory, localRepository, artifactMetadataSource, artifactCollector,
+      runner.addExtensions(session, getLog(), lifecycleExecutor, artifactFactory, localRepository, artifactMetadataSource, artifactCollector,
         dependencyTreeBuilder, projectBuilder);
-    if (getLog().isDebugEnabled()) {
-      runner.setProperty("sonar.verbose", "true");
+      if (getLog().isDebugEnabled()) {
+        runner.setProperty("sonar.verbose", "true");
+      }
+      runner.execute();
+    } catch (Exception e) {
+      throw ExceptionHandling.handle(e, getLog());
     }
-    runner.execute();
   }
 
   private ArtifactVersion getMavenVersion() {
diff --git a/sonar-maven-plugin/src/test/java/org/sonar/maven/ExceptionHandlingTest.java b/sonar-maven-plugin/src/test/java/org/sonar/maven/ExceptionHandlingTest.java
new file mode 100644 (file)
index 0000000..59d579f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.junit.Test;
+import org.sonar.runner.impl.RunnerException;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class ExceptionHandlingTest {
+
+  private static final String MESSAGE = "the error message";
+
+  @Test
+  public void should_log_message_and_throw_exception() throws Exception {
+    Log log = mock(Log.class);
+    try {
+      ExceptionHandling.handle(MESSAGE, log);
+      fail();
+    } catch (MojoExecutionException e) {
+      assertThat(e.getMessage()).isEqualTo(MESSAGE);
+      verify(log).error(MESSAGE);
+    }
+  }
+
+  @Test
+  public void should_log_message_and_rethrow_exception() throws Exception {
+    Log log = mock(Log.class);
+    IllegalStateException cause = new IllegalStateException(MESSAGE);
+    try {
+      ExceptionHandling.handle(cause, log);
+      fail();
+    } catch (MojoExecutionException e) {
+      assertThat(e.getMessage()).isEqualTo(MESSAGE);
+      assertThat(e.getCause()).isSameAs(cause);
+      verify(log).error(MESSAGE);
+    }
+  }
+
+  @Test
+  public void should_hide_sonar_runner_stacktrace() throws Exception {
+    Log log = mock(Log.class);
+    IllegalStateException cause = new IllegalStateException(MESSAGE);
+    try {
+      ExceptionHandling.handle(new RunnerException(cause), log);
+      fail();
+    } catch (MojoExecutionException e) {
+      assertThat(e.getMessage()).isEqualTo(MESSAGE);
+      assertThat(e.getCause()).isSameAs(cause);
+      verify(log).error(MESSAGE);
+    }
+  }
+}
diff --git a/sonar-maven-plugin/src/test/java/org/sonar/runner/impl/RunnerException.java b/sonar-maven-plugin/src/test/java/org/sonar/runner/impl/RunnerException.java
new file mode 100644 (file)
index 0000000..aff129c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.runner.impl;
+
+public class RunnerException extends RuntimeException {
+  public RunnerException(Throwable throwable) {
+    super(throwable);
+  }
+}
index 25290dac9b2bc42bb7c17910e013b5c72a6994c8..fc41e59c26fdd6cafbd14172b6c0558a040e7475 100644 (file)
 package org.sonar.api.utils;
 
 /**
- * Runtime exception for "functional" errors. It aims to be displayed to end-users, without any technical information
- * like stack traces.
+ * Runtime exception for "functional" error. It aims to be displayed to end-users, without any technical information
+ * like stack traces. It requires sonar-runner 2.4. Previous versions log stack trace.
+ * <p/>
+ * Note that by design Maven still logs the stack trace when the option -e is set.
  *
  * @since 4.0
  */
 public class MessageException extends RuntimeException {
 
-  public MessageException(String s) {
-    super(s);
+  private MessageException(String message) {
+    super(message);
   }
 
-  /**
-   * Does not fill in the stack trace
-   *
-   * @see java.lang.Throwable#fillInStackTrace()
-   */
-  @Override
-  public synchronized Throwable fillInStackTrace() {
-    return this;
+  public static MessageException of(String message) {
+    return new MessageException(message);
   }
 
-  @Override
-  public String toString() {
-    return getMessage();
-  }
-
-
 }
index 0b734416e947b8b9822d7439275785b1313ea2ef..77daa814d376a25348d393b965ba4bb6f253a354 100644 (file)
@@ -21,30 +21,15 @@ package org.sonar.api.utils;
 
 import org.junit.Test;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
 import static org.fest.assertions.Assertions.assertThat;
 
 public class MessageExceptionTest {
 
-  /**
-   * The exception should log only the message, without the "org.sonar.api.utils.MessageException" prefix
-   * and stack traces
-   */
   @Test
-  public void should_not_print_stacktrace() throws Exception {
+  public void should_create_exception() throws Exception {
     String message = "the message";
-    try {
-      throw new MessageException(message);
-
-    } catch (MessageException e) {
-      StringWriter writer = new StringWriter();
-      e.printStackTrace(new PrintWriter(writer));
-
-      assertThat(e.getStackTrace()).isEmpty();
-      assertThat(e.getMessage()).isEqualTo(message);
-      assertThat(writer.toString()).isEqualTo(message + System.getProperty("line.separator"));
-    }
+    MessageException exception = MessageException.of(message);
+    assertThat(exception.getMessage()).isEqualTo(message);
+    assertThat(exception).isInstanceOf(RuntimeException.class);
   }
 }
index a8fb1a922a4a8275d3f888dd1941f893c02f072b..12043a4fdd94765ed6cd5e2c7884a427eec4ba7c 100644 (file)
@@ -35,7 +35,7 @@ public class DatabaseServerCompatibility implements ServerComponent {
   public void start() {
     DatabaseVersion.Status status = version.getStatus();
     if (status== DatabaseVersion.Status.REQUIRES_DOWNGRADE) {
-      throw new MessageException("Database relates to a more recent version of sonar. Please check your settings.");
+      throw MessageException.of("Database relates to a more recent version of sonar. Please check your settings.");
     }
     if (status== DatabaseVersion.Status.REQUIRES_UPGRADE) {
       LoggerFactory.getLogger(DatabaseServerCompatibility.class).info("Database must be upgraded. Please browse /setup");