]> source.dussan.org Git - sonarqube.git/commitdiff
Fix some quality flaws
authorSimon Brandhof <simon.brandhof@gmail.com>
Thu, 30 May 2013 09:13:00 +0000 (11:13 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Thu, 30 May 2013 09:13:10 +0000 (11:13 +0200)
24 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/notification/SendIssueNotificationsPostJob.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/SourceChecksum.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/ViolationTrackingBlocksRecognizer.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/NewAlerts.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/notification/SendIssueNotificationsPostJobTest.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/notifications/alerts/NewAlertsTest.java
sonar-core/src/main/java/org/sonar/core/issue/IssueNotifications.java
sonar-server/src/dev/web.xml
sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java
sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
sonar-server/src/main/java/org/sonar/server/issue/IssueCommentService.java
sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
sonar-server/src/main/java/org/sonar/server/issue/IssueStatsFinder.java
sonar-server/src/main/java/org/sonar/server/platform/UserSession.java [deleted file]
sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java [deleted file]
sonar-server/src/main/java/org/sonar/server/rule/RubyRuleService.java
sonar-server/src/main/java/org/sonar/server/user/UserSession.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/web.xml
sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/platform/UserSessionTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java
sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java [new file with mode: 0644]

index 7bfa21586c98b19463abde6c2665377768e22b0c..8f758e0ea1a01295aa63c10f3a5014f713adf603 100644 (file)
@@ -58,7 +58,10 @@ public class SendIssueNotificationsPostJob implements PostJob {
       }
       if (issue.isChanged() && issue.diffs() != null) {
         Rule rule = ruleFinder.findByKey(issue.ruleKey());
-        notifications.sendChanges(issue, context, rule, project, null);
+        // TODO warning - rules with status REMOVED are currently ignored, but should not
+        if (rule != null) {
+          notifications.sendChanges(issue, context, rule, project, null);
+        }
       }
     }
     if (newIssues > 0) {
index b797bf4d1f2d849ddae138a1d965ac3e27a49494..5662276aee1bba808bb7dfe524551bf5f17bd7cf 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.collect.Lists;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang.StringUtils;
 
+import javax.annotation.Nullable;
 import java.util.List;
 
 public final class SourceChecksum {
@@ -37,7 +38,7 @@ public final class SourceChecksum {
    * @param line line number (first line has number 1)
    * @return checksum or null if checksum not exists for line
    */
-  public static String getChecksumForLine(List<String> checksums, Integer line) {
+  public static String getChecksumForLine(List<String> checksums, @Nullable Integer line) {
     if (line == null || line < 1 || line > checksums.size()) {
       return null;
     }
index b1965882a733d43ff918ad659333a063dbfa020f..2a191e3d62e2b849c090d59a179b95f5c1789c05 100644 (file)
@@ -25,6 +25,8 @@ import org.sonar.plugins.core.issue.tracking.HashedSequenceComparator;
 import org.sonar.plugins.core.issue.tracking.StringText;
 import org.sonar.plugins.core.issue.tracking.StringTextComparator;
 
+import javax.annotation.Nullable;
+
 public class ViolationTrackingBlocksRecognizer {
 
   private final HashedSequence<StringText> a;
@@ -44,11 +46,11 @@ public class ViolationTrackingBlocksRecognizer {
     this.cmp = cmp;
   }
 
-  public boolean isValidLineInReference(Integer line) {
+  public boolean isValidLineInReference(@Nullable Integer line) {
     return (line != null) && (0 <= line - 1) && (line - 1 < a.length());
   }
 
-  public boolean isValidLineInSource(Integer line) {
+  public boolean isValidLineInSource(@Nullable Integer line) {
     return (line != null) && (0 <= line - 1) && (line - 1 < b.length());
   }
 
index 1a5211455166f39c1f6528eb7e17dc2ba80e233a..606fd22a34a84aa93e7f9db56157508f6aac147b 100644 (file)
@@ -53,15 +53,17 @@ public class NewAlerts extends NotificationDispatcher {
 
   @Override
   public void dispatch(Notification notification, Context context) {
-    int projectId = Integer.parseInt(notification.getFieldValue("projectId"));
-    Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(this, projectId);
+    String projectIdString = notification.getFieldValue("projectId");
+    if (projectIdString != null) {
+      int projectId = Integer.parseInt(projectIdString);
+      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(this, projectId);
 
-    for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
-      String userLogin = channelsByRecipients.getKey();
-      for (NotificationChannel channel : channelsByRecipients.getValue()) {
-        context.addUser(userLogin, channel);
+      for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
+        String userLogin = channelsByRecipients.getKey();
+        for (NotificationChannel channel : channelsByRecipients.getValue()) {
+          context.addUser(userLogin, channel);
+        }
       }
     }
   }
-
 }
index 66943aa710bfd9129734c4ecc76cd72c7150123f..2262e3e80f18ac4f8df61f1c70328aab5e101772 100644 (file)
@@ -24,11 +24,16 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.batch.SensorContext;
+import org.sonar.api.component.Component;
+import org.sonar.api.issue.Issue;
 import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
 import org.sonar.core.issue.IssueNotifications;
 
 import java.util.Arrays;
@@ -78,4 +83,42 @@ public class SendIssueNotificationsPostJobTest {
 
     verifyZeroInteractions(notifications);
   }
+
+  @Test
+  public void should_send_notif_if_issue_change() throws Exception {
+
+    when(project.getAnalysisDate()).thenReturn(DateUtils.parseDate("2013-05-18"));
+    RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
+    Rule rule = new Rule("squid", "AvoidCycles");
+    DefaultIssue issue = new DefaultIssue()
+      .setChanged(true)
+      .setFieldDiff(mock(IssueChangeContext.class), "severity", "MINOR", "BLOCKER")
+      .setRuleKey(ruleKey);
+    when(issueCache.all()).thenReturn(Arrays.asList(issue));
+    when(ruleFinder.findByKey(ruleKey)).thenReturn(rule);
+
+    SendIssueNotificationsPostJob job = new SendIssueNotificationsPostJob(issueCache, notifications, ruleFinder);
+    job.executeOn(project, sensorContext);
+
+    verify(notifications).sendChanges(eq(issue), any(IssueChangeContext.class), eq(rule), any(Component.class), (Component)isNull());
+  }
+
+  @Test
+  public void should_not_send_notif_if_issue_change_on_removed_rule() throws Exception {
+    IssueChangeContext changeContext = mock(IssueChangeContext.class);
+
+    when(project.getAnalysisDate()).thenReturn(DateUtils.parseDate("2013-05-18"));
+    RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
+    DefaultIssue issue = new DefaultIssue()
+      .setChanged(true)
+      .setFieldDiff(changeContext, "severity", "MINOR", "BLOCKER")
+      .setRuleKey(ruleKey);
+    when(issueCache.all()).thenReturn(Arrays.asList(issue));
+    when(ruleFinder.findByKey(ruleKey)).thenReturn(null);
+
+    SendIssueNotificationsPostJob job = new SendIssueNotificationsPostJob(issueCache, notifications, ruleFinder);
+    job.executeOn(project, sensorContext);
+
+    verify(notifications, never()).sendChanges(eq(issue), eq(changeContext), any(Rule.class), any(Component.class), any(Component.class));
+  }
 }
index b1fa5976b2e27a960f73da94a74e6081e1867089..8fdab8da824314afb5620fbd2deb5cdb84b919c5 100644 (file)
@@ -21,42 +21,22 @@ package org.sonar.plugins.core.notifications.alerts;
 
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
-import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
 import org.sonar.api.notifications.NotificationDispatcher;
 import org.sonar.api.notifications.NotificationManager;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 public class NewAlertsTest {
 
-  @Mock
-  private NotificationManager notificationManager;
-
-  @Mock
-  private NotificationDispatcher.Context context;
-
-  @Mock
-  private NotificationChannel emailChannel;
-
-  @Mock
-  private NotificationChannel twitterChannel;
-
-  private NewAlerts dispatcher;
-
-  @Before
-  public void init() {
-    MockitoAnnotations.initMocks(this);
-    dispatcher = new NewAlerts(notificationManager);
-  }
+  NotificationManager notificationManager = mock(NotificationManager.class);
+  NotificationDispatcher.Context context = mock(NotificationDispatcher.Context.class);
+  NotificationChannel emailChannel = mock(NotificationChannel.class);
+  NotificationChannel twitterChannel = mock(NotificationChannel.class);
+  NewAlerts dispatcher = new NewAlerts(notificationManager);
 
   @Test
   public void should_not_dispatch_if_not_alerts_notification() throws Exception {
@@ -81,4 +61,17 @@ public class NewAlertsTest {
     verifyNoMoreInteractions(context);
   }
 
+  @Test
+  public void should_not_dispatch_if_missing_project_id() {
+    Multimap<String, NotificationChannel> recipients = HashMultimap.create();
+    recipients.put("user1", emailChannel);
+    recipients.put("user2", twitterChannel);
+    when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, 34)).thenReturn(recipients);
+
+    Notification notification = new Notification("alerts");
+    dispatcher.performDispatch(notification, context);
+
+    verifyNoMoreInteractions(context);
+  }
+
 }
index b57f001b3daf2b00482ced4e72f49e11eb6b2430..0fc2debfc0984990cc0a9b3b89ee6d02a5597ef0 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.rules.Rule;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.core.i18n.RuleI18nManager;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import java.util.Locale;
 import java.util.Map;
@@ -58,31 +59,36 @@ public class IssueNotifications implements BatchComponent, ServerComponent {
     return notification;
   }
 
+  @CheckForNull
   public Notification sendChanges(DefaultIssue issue, IssueChangeContext context, IssueQueryResult queryResult) {
     return sendChanges(issue, context, queryResult.rule(issue), queryResult.project(issue), queryResult.component(issue));
   }
 
+  @CheckForNull
   public Notification sendChanges(DefaultIssue issue, IssueChangeContext context, Rule rule, Component project, @Nullable Component component) {
-    Notification notification = newNotification(project, "issue-changes");
-    notification.setFieldValue("key", issue.key());
-    notification.setFieldValue("changeAuthor", context.login());
-    notification.setFieldValue("reporter", issue.reporter());
-    notification.setFieldValue("assignee", issue.assignee());
-    notification.setFieldValue("message", issue.message());
-    notification.setFieldValue("ruleName", ruleName(rule));
-    notification.setFieldValue("componentKey", issue.componentKey());
-    if (component != null) {
-      notification.setFieldValue("componentName", component.name());
-    }
+    if (issue.diffs() != null) {
+      Notification notification = newNotification(project, "issue-changes");
+      notification.setFieldValue("key", issue.key());
+      notification.setFieldValue("changeAuthor", context.login());
+      notification.setFieldValue("reporter", issue.reporter());
+      notification.setFieldValue("assignee", issue.assignee());
+      notification.setFieldValue("message", issue.message());
+      notification.setFieldValue("ruleName", ruleName(rule));
+      notification.setFieldValue("componentKey", issue.componentKey());
+      if (component != null) {
+        notification.setFieldValue("componentName", component.name());
+      }
 
-    for (Map.Entry<String, FieldDiffs.Diff> entry : issue.diffs().diffs().entrySet()) {
-      String type = entry.getKey();
-      FieldDiffs.Diff diff = entry.getValue();
-      notification.setFieldValue("old." + type, diff.oldValue() != null ? diff.oldValue().toString() : null);
-      notification.setFieldValue("new." + type, diff.newValue() != null ? diff.newValue().toString() : null);
+      for (Map.Entry<String, FieldDiffs.Diff> entry : issue.diffs().diffs().entrySet()) {
+        String type = entry.getKey();
+        FieldDiffs.Diff diff = entry.getValue();
+        notification.setFieldValue("old." + type, diff.oldValue() != null ? diff.oldValue().toString() : null);
+        notification.setFieldValue("new." + type, diff.newValue() != null ? diff.newValue().toString() : null);
+      }
+      notificationsManager.scheduleForSending(notification);
+      return notification;
     }
-    notificationsManager.scheduleForSending(notification);
-    return notification;
+    return null;
   }
 
   private String ruleName(@Nullable Rule rule) {
index 73445144d8bd2f16915d31b1e4988912802f3bb8..fef16ea1aafc815f4ee76487ef407adf044204dc 100644 (file)
@@ -42,7 +42,7 @@
   </filter>
   <filter>
     <filter-name>UserSessionFilter</filter-name>
-    <filter-class>org.sonar.server.platform.UserSessionFilter</filter-class>
+    <filter-class>org.sonar.server.user.UserSessionFilter</filter-class>
   </filter>
   <filter>
     <filter-name>RackFilter</filter-name>
index 0f099d0f2590bf774cbbe3eb762b1f760447b9dd..c983cac184d9efbff83c13a5f457f40f9e99f772 100644 (file)
@@ -40,7 +40,7 @@ import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.rule.DefaultRuleFinder;
 import org.sonar.core.user.AuthorizationDao;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 import java.util.Collection;
 import java.util.List;
index 1b4ac5a61b252120a781dd0a7439ba52df1d5d83..05ea65440dd49bdac148567c9dd3537a71e704ed 100644 (file)
@@ -38,7 +38,7 @@ import org.sonar.core.issue.workflow.Transition;
 import org.sonar.core.resource.ResourceDao;
 import org.sonar.core.resource.ResourceDto;
 import org.sonar.core.resource.ResourceQuery;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 import org.sonar.server.util.RubyUtils;
 
 import javax.annotation.Nullable;
index 5095ce59d3747c4fc3d0b76227b0aa4dc4d4a258..8a5180285144582d5d34e5419a827f7c80c90972 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueChangeDao;
 import org.sonar.core.issue.db.IssueChangeDto;
 import org.sonar.core.issue.db.IssueStorage;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 import java.util.Date;
 
index b3f8b8521f69a75cf532aa577f54e5e41b7ca645..27f0b0efbbcdbc7950f4c1a6b0964387388259a4 100644 (file)
@@ -34,7 +34,7 @@ import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueStorage;
 import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.issue.workflow.Transition;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 import javax.annotation.Nullable;
 
index a19829113f0dea627f4c07d3d5750af41e39ef24..561272244d444f7144e7d97d051cbb496b01e248 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.core.issue.db.IssueStatsColumn;
 import org.sonar.core.issue.db.IssueStatsDao;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 import javax.annotation.CheckForNull;
 
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/UserSession.java b/sonar-server/src/main/java/org/sonar/server/platform/UserSession.java
deleted file mode 100644 (file)
index c81409d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.server.platform;
-
-import com.google.common.base.Objects;
-import org.sonar.server.ui.JRubyI18n;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import java.util.Locale;
-
-public class UserSession {
-
-  private static final ThreadLocal<UserSession> THREAD_LOCAL = new ThreadLocal<UserSession>();
-  private static final UserSession DEFAULT_ANONYMOUS = new UserSession(null, null, Locale.ENGLISH);
-
-  private final Integer userId;
-  private final String login;
-  private final Locale locale;
-
-  public UserSession(@Nullable Integer userId, @Nullable String login, @Nullable Locale locale) {
-    this.userId = userId;
-    this.login = login;
-    this.locale = Objects.firstNonNull(locale, Locale.ENGLISH);
-  }
-
-  @CheckForNull
-  public String login() {
-    return login;
-  }
-
-  @CheckForNull
-  public Integer userId() {
-    return userId;
-  }
-
-  public boolean isLoggedIn() {
-    return userId != null;
-  }
-
-  public Locale locale() {
-    return locale;
-  }
-
-  /**
-   * @return never null
-   */
-  public static UserSession get() {
-    return Objects.firstNonNull(THREAD_LOCAL.get(), DEFAULT_ANONYMOUS);
-  }
-
-  public static void set(@Nullable UserSession session) {
-    THREAD_LOCAL.set(session);
-  }
-
-  public static void setSession(@Nullable Integer userId, @Nullable String login, @Nullable String localeRubyKey) {
-    set(new UserSession(userId, login, JRubyI18n.toLocale(localeRubyKey)));
-  }
-
-  public static void remove() {
-    THREAD_LOCAL.remove();
-  }
-
-  static boolean hasSession() {
-    return THREAD_LOCAL.get() != null;
-  }
-}
-
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java b/sonar-server/src/main/java/org/sonar/server/platform/UserSessionFilter.java
deleted file mode 100644 (file)
index 8727442..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.server.platform;
-
-import javax.servlet.*;
-import java.io.IOException;
-
-public class UserSessionFilter implements Filter {
-  @Override
-  public void init(FilterConfig filterConfig) throws ServletException {
-  }
-
-  @Override
-  public void destroy() {
-  }
-
-  @Override
-  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
-    try {
-      chain.doFilter(servletRequest, servletResponse);
-    } finally {
-      UserSession.remove();
-    }
-  }
-}
index 9a61e560eae490ae0ab8cf49235126d05e6d2a8c..0bd88c37885807e3dadaaedec6fe521e2fd24ab5 100644 (file)
@@ -23,7 +23,7 @@ import org.picocontainer.Startable;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.rules.Rule;
 import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 /**
  * Used through ruby code <pre>Internal.rules</pre>
diff --git a/sonar-server/src/main/java/org/sonar/server/user/UserSession.java b/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
new file mode 100644 (file)
index 0000000..87fbe6a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.server.user;
+
+import com.google.common.base.Objects;
+import org.sonar.server.ui.JRubyI18n;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.util.Locale;
+
+/**
+ * Part of the current HTTP session
+ *
+ * @since 3.6
+ */
+public class UserSession {
+
+  private static final ThreadLocal<UserSession> THREAD_LOCAL = new ThreadLocal<UserSession>();
+  private static final UserSession DEFAULT_ANONYMOUS = new UserSession(null, null, Locale.ENGLISH);
+
+  private final Integer userId;
+  private final String login;
+  private final Locale locale;
+
+  public UserSession(@Nullable Integer userId, @Nullable String login, @Nullable Locale locale) {
+    this.userId = userId;
+    this.login = login;
+    this.locale = Objects.firstNonNull(locale, Locale.ENGLISH);
+  }
+
+  @CheckForNull
+  public String login() {
+    return login;
+  }
+
+  @CheckForNull
+  public Integer userId() {
+    return userId;
+  }
+
+  public boolean isLoggedIn() {
+    return userId != null;
+  }
+
+  public Locale locale() {
+    return locale;
+  }
+
+  /**
+   * @return never null
+   */
+  public static UserSession get() {
+    return Objects.firstNonNull(THREAD_LOCAL.get(), DEFAULT_ANONYMOUS);
+  }
+
+  public static void set(@Nullable UserSession session) {
+    THREAD_LOCAL.set(session);
+  }
+
+  public static void setSession(@Nullable Integer userId, @Nullable String login, @Nullable String localeRubyKey) {
+    set(new UserSession(userId, login, JRubyI18n.toLocale(localeRubyKey)));
+  }
+
+  public static void remove() {
+    THREAD_LOCAL.remove();
+  }
+
+  static boolean hasSession() {
+    return THREAD_LOCAL.get() != null;
+  }
+}
+
diff --git a/sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java b/sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java
new file mode 100644 (file)
index 0000000..80b6613
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.server.user;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+/**
+ * @since 3.6
+ */
+public class UserSessionFilter implements Filter {
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+  }
+
+  @Override
+  public void destroy() {
+  }
+
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+    try {
+      chain.doFilter(servletRequest, servletResponse);
+    } finally {
+      UserSession.remove();
+    }
+  }
+}
index 55b93f2f7da91ee13cf8eb4ec7d73bc84d2499f1..2249a67997af64db4a83bc6a99003f47501a13ec 100644 (file)
@@ -42,7 +42,7 @@
   </filter>
   <filter>
     <filter-name>UserSessionFilter</filter-name>
-    <filter-class>org.sonar.server.platform.UserSessionFilter</filter-class>
+    <filter-class>org.sonar.server.user.UserSessionFilter</filter-class>
   </filter>
   <filter>
     <filter-name>RackFilter</filter-name>
diff --git a/sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java b/sonar-server/src/test/java/org/sonar/server/platform/UserSessionFilterTest.java
deleted file mode 100644 (file)
index edcc91f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.server.platform;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import java.util.Locale;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class UserSessionFilterTest {
-
-  @Before
-  public void setUp() {
-    // for test isolation
-    UserSession.remove();
-  }
-
-  @Test
-  public void should_cleanup_user_session_after_request_handling() throws Exception {
-    HttpServletRequest httpRequest = mock(HttpServletRequest.class);
-    ServletResponse httpResponse = mock(ServletResponse.class);
-    FilterChain chain = mock(FilterChain.class);
-
-    UserSession.set(new UserSession(123, "karadoc", Locale.CANADA_FRENCH));
-    assertThat(UserSession.hasSession()).isTrue();
-    UserSessionFilter filter = new UserSessionFilter();
-    filter.doFilter(httpRequest, httpResponse, chain);
-
-    verify(chain).doFilter(httpRequest, httpResponse);
-    assertThat(UserSession.hasSession()).isFalse();
-  }
-
-  @Test
-  public void just_for_fun_and_coverage() throws Exception {
-    UserSessionFilter filter = new UserSessionFilter();
-    filter.init(mock(FilterConfig.class));
-    filter.destroy();
-    // do not fail
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/platform/UserSessionTest.java b/sonar-server/src/test/java/org/sonar/server/platform/UserSessionTest.java
deleted file mode 100644 (file)
index 4a14af1..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.server.platform;
-
-import org.junit.Test;
-
-import java.util.Locale;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class UserSessionTest {
-  @Test
-  public void should_get_anonymous_session_by_default() throws Exception {
-    UserSession.remove();
-
-    UserSession session = UserSession.get();
-
-    assertThat(session).isNotNull();
-    assertThat(session.login()).isNull();
-    assertThat(session.userId()).isNull();
-    assertThat(session.isLoggedIn()).isFalse();
-    // default locale
-    assertThat(session.locale()).isEqualTo(Locale.ENGLISH);
-  }
-
-  @Test
-  public void should_set_session_from_jror() throws Exception {
-    UserSession.setSession(123, "karadoc", "fr");
-
-    UserSession session = UserSession.get();
-
-    assertThat(session).isNotNull();
-    assertThat(session.login()).isEqualTo("karadoc");
-    assertThat(session.userId()).isEqualTo(123);
-    assertThat(session.isLoggedIn()).isTrue();
-    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
-  }
-
-  @Test
-  public void should_set_anonymous_session_from_jror() throws Exception {
-    UserSession.setSession(null, null, "fr");
-
-    UserSession session = UserSession.get();
-
-    assertThat(session).isNotNull();
-    assertThat(session.login()).isNull();
-    assertThat(session.userId()).isNull();
-    assertThat(session.isLoggedIn()).isFalse();
-    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
-  }
-
-  @Test
-  public void should_get_session() throws Exception {
-    UserSession.set(new UserSession(123, "karadoc", Locale.FRENCH));
-
-    UserSession session = UserSession.get();
-    assertThat(session).isNotNull();
-    assertThat(session.userId()).isEqualTo(123);
-    assertThat(session.login()).isEqualTo("karadoc");
-    assertThat(session.isLoggedIn()).isTrue();
-    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
-  }
-}
index ec7e19e6fc91c92efd05417d8da7c61ad9c750e2..be0cbdad32be7eea736ad152438ac93db3fd1ba5 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.rule;
 import org.junit.Test;
 import org.sonar.api.rules.Rule;
 import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.server.platform.UserSession;
+import org.sonar.server.user.UserSession;
 
 import java.util.Locale;
 
diff --git a/sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java b/sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java
new file mode 100644 (file)
index 0000000..496a841
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.server.user;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class UserSessionFilterTest {
+
+  @Before
+  public void setUp() {
+    // for test isolation
+    UserSession.remove();
+  }
+
+  @Test
+  public void should_cleanup_user_session_after_request_handling() throws Exception {
+    HttpServletRequest httpRequest = mock(HttpServletRequest.class);
+    ServletResponse httpResponse = mock(ServletResponse.class);
+    FilterChain chain = mock(FilterChain.class);
+
+    UserSession.set(new UserSession(123, "karadoc", Locale.CANADA_FRENCH));
+    assertThat(UserSession.hasSession()).isTrue();
+    UserSessionFilter filter = new UserSessionFilter();
+    filter.doFilter(httpRequest, httpResponse, chain);
+
+    verify(chain).doFilter(httpRequest, httpResponse);
+    assertThat(UserSession.hasSession()).isFalse();
+  }
+
+  @Test
+  public void just_for_fun_and_coverage() throws Exception {
+    UserSessionFilter filter = new UserSessionFilter();
+    filter.init(mock(FilterConfig.class));
+    filter.destroy();
+    // do not fail
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java b/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java
new file mode 100644 (file)
index 0000000..3c696a1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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.server.user;
+
+import org.junit.Test;
+import org.sonar.server.user.UserSession;
+
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class UserSessionTest {
+  @Test
+  public void should_get_anonymous_session_by_default() throws Exception {
+    UserSession.remove();
+
+    UserSession session = UserSession.get();
+
+    assertThat(session).isNotNull();
+    assertThat(session.login()).isNull();
+    assertThat(session.userId()).isNull();
+    assertThat(session.isLoggedIn()).isFalse();
+    // default locale
+    assertThat(session.locale()).isEqualTo(Locale.ENGLISH);
+  }
+
+  @Test
+  public void should_set_session_from_jror() throws Exception {
+    UserSession.setSession(123, "karadoc", "fr");
+
+    UserSession session = UserSession.get();
+
+    assertThat(session).isNotNull();
+    assertThat(session.login()).isEqualTo("karadoc");
+    assertThat(session.userId()).isEqualTo(123);
+    assertThat(session.isLoggedIn()).isTrue();
+    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
+  }
+
+  @Test
+  public void should_set_anonymous_session_from_jror() throws Exception {
+    UserSession.setSession(null, null, "fr");
+
+    UserSession session = UserSession.get();
+
+    assertThat(session).isNotNull();
+    assertThat(session.login()).isNull();
+    assertThat(session.userId()).isNull();
+    assertThat(session.isLoggedIn()).isFalse();
+    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
+  }
+
+  @Test
+  public void should_get_session() throws Exception {
+    UserSession.set(new UserSession(123, "karadoc", Locale.FRENCH));
+
+    UserSession session = UserSession.get();
+    assertThat(session).isNotNull();
+    assertThat(session.userId()).isEqualTo(123);
+    assertThat(session.login()).isEqualTo("karadoc");
+    assertThat(session.isLoggedIn()).isTrue();
+    assertThat(session.locale()).isEqualTo(Locale.FRENCH);
+  }
+}