]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3323 Display tab/page/widget only when required measures exist
authorFabrice Bellingard <bellingard@gmail.com>
Thu, 22 Mar 2012 13:44:11 +0000 (14:44 +0100)
committerFabrice Bellingard <bellingard@gmail.com>
Thu, 22 Mar 2012 13:48:17 +0000 (14:48 +0100)
=> new annotation @RequiredMeasure(mandatory={}, oneOf={}) that can
   be applied on any views.
   Tested on pages, tabs and widgets

sonar-plugin-api/src/main/java/org/sonar/api/web/RequiredMeasures.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
sonar-server/src/main/java/org/sonar/server/ui/ViewProxy.java
sonar-server/src/main/java/org/sonar/server/ui/Views.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/drilldown_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/snapshot.rb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-server/src/test/java/org/sonar/server/ui/ViewProxyTest.java
sonar-server/src/test/java/org/sonar/server/ui/ViewsTest.java

diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/RequiredMeasures.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/RequiredMeasures.java
new file mode 100644 (file)
index 0000000..f89cbdd
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.api.web;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <p>
+ * Annotation used to specify which measures should be available on a snapshot to be able to display a view (page, tab, ...).
+ * It is possible to give a list of mandatory measures (= if one is not available, the view is not displayed) and/or a list of
+ * needed measures (only one of them needs to be available). The measures are specified using the metric keys.
+ * </p>
+ * <p>
+ * Example: the DesignPage absolutely requires the "dsm" measure to be fed in order to be displayed, whatever the language.
+ * The class will define a <code>@RequiredMeasures(mandatory={"dsm"})</code> annotation. 
+ * </p>
+ * 
+ * @since 2.15
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RequiredMeasures {
+
+  /**
+   * Lists all the measures that must absolutely to be available on the snapshot in order to display the view.
+   * @return the list of mandatory measures, identified by their metric key
+   */
+  String[] mandatory() default {};
+
+  /**
+   * Lists all needed measures required to display the view. If only one of them is available on the snapshot, then the view 
+   * is displayed.
+   * @return the list of needed measures, identified by their metric key
+   */
+  String[] oneOf() default {};
+
+}
index 76517e30df8dded4b1ab89e50a0e548361b41604..be0d7388ac390297490a864ca065217bd64aa050 100644 (file)
@@ -153,8 +153,8 @@ public final class JRubyFacade {
   }
 
 
-  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage) {
-    return getContainer().getComponentByType(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage);
+  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage, Object[] availableMeasures) {
+    return getContainer().getComponentByType(Views.class).getWidgets(resourceScope, resourceQualifier, resourceLanguage, (String[]) availableMeasures);
   }
 
   public List<ViewProxy<Widget>> getWidgets() {
@@ -165,20 +165,20 @@ public final class JRubyFacade {
     return getContainer().getComponentByType(Views.class).getWidget(id);
   }
 
-  public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage) {
-    return getContainer().getComponentByType(Views.class).getPages(section, resourceScope, resourceQualifier, resourceLanguage);
+  public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage, Object[] availableMeasures) {
+    return getContainer().getComponentByType(Views.class).getPages(section, resourceScope, resourceQualifier, resourceLanguage, (String[]) availableMeasures);
   }
 
   public List<ViewProxy<Page>> getResourceTabs() {
-    return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, null, null, null);
+    return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, null, null, null, null);
   }
 
-  public List<ViewProxy<Page>> getResourceTabs(String scope, String qualifier, String language) {
-    return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, scope, qualifier, language);
+  public List<ViewProxy<Page>> getResourceTabs(String scope, String qualifier, String language, Object[] availableMeasures) {
+    return getContainer().getComponentByType(Views.class).getPages(NavigationSection.RESOURCE_TAB, scope, qualifier, language, (String[]) availableMeasures);
   }
 
-  public List<ViewProxy<Page>> getResourceTabsForMetric(String scope, String qualifier, String language, String metric) {
-    return getContainer().getComponentByType(Views.class).getPagesForMetric(NavigationSection.RESOURCE_TAB, scope, qualifier, language, metric);
+  public List<ViewProxy<Page>> getResourceTabsForMetric(String scope, String qualifier, String language, Object[] availableMeasures, String metric) {
+    return getContainer().getComponentByType(Views.class).getPagesForMetric(NavigationSection.RESOURCE_TAB, scope, qualifier, language, (String[]) availableMeasures, metric);
   }
 
   public ViewProxy<Page> getPage(String id) {
index e7d09cbcf7ddcb1784627d91d9a893e473cbfef4..eb8822713fac36f5dfa7f7cb80fcb69dae5316d2 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.web.*;
 import java.util.Collection;
 import java.util.Map;
 
+@SuppressWarnings("rawtypes")
 public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
 
   private V view;
@@ -46,35 +47,66 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
   private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
   private boolean isDefaultTab = false;
   private boolean isWidget = false;
+  private String[] mandatoryMeasures = {};
+  private String[] needOneOfMeasures = {};
 
   public ViewProxy(final V view) {
     this.view = view;
 
-    UserRole userRoleAnnotation = AnnotationUtils.getClassAnnotation(view, UserRole.class);
-    if (userRoleAnnotation != null) {
-      userRoles = userRoleAnnotation.value();
+    initUserRoles(view);
+    initSections(view);
+    initResourceScope(view);
+    initResourceQualifier(view);
+    initResourceLanguage(view);
+    initDefaultTabInfo(view);
+    initDescription(view);
+    initWidgetProperties(view);
+    initWidgetCategory(view);
+    initWidgetLayout(view);
+    initRequiredMeasures(view);
+
+    isWidget = (view instanceof Widget);
+  }
+
+  private void initRequiredMeasures(V view) {
+    RequiredMeasures requiredMeasuresAnnotation = AnnotationUtils.getClassAnnotation(view, RequiredMeasures.class);
+    if (requiredMeasuresAnnotation != null) {
+      mandatoryMeasures = requiredMeasuresAnnotation.mandatory();
+      needOneOfMeasures = requiredMeasuresAnnotation.oneOf();
     }
+  }
 
-    NavigationSection sectionAnnotation = AnnotationUtils.getClassAnnotation(view, NavigationSection.class);
-    if (sectionAnnotation != null) {
-      sections = sectionAnnotation.value();
+  private void initWidgetLayout(final V view) {
+    WidgetLayout layoutAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetLayout.class);
+    if (layoutAnnotation != null) {
+      widgetLayout = layoutAnnotation.value();
     }
+  }
 
-    ResourceScope scopeAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceScope.class);
-    if (scopeAnnotation != null) {
-      resourceScopes = scopeAnnotation.value();
+  private void initWidgetCategory(final V view) {
+    WidgetCategory categAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetCategory.class);
+    if (categAnnotation != null) {
+      widgetCategories = categAnnotation.value();
     }
+  }
 
-    ResourceQualifier qualifierAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceQualifier.class);
-    if (qualifierAnnotation != null) {
-      resourceQualifiers = qualifierAnnotation.value();
+  private void initWidgetProperties(final V view) {
+    WidgetProperties propAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetProperties.class);
+    if (propAnnotation != null) {
+      for (WidgetProperty property : propAnnotation.value()) {
+        widgetPropertiesByKey.put(property.key(), property);
+      }
     }
+  }
 
-    ResourceLanguage languageAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceLanguage.class);
-    if (languageAnnotation != null) {
-      resourceLanguages = languageAnnotation.value();
+  private void initDescription(final V view) {
+    Description descriptionAnnotation = AnnotationUtils.getClassAnnotation(view, Description.class);
+    if (descriptionAnnotation != null) {
+      description = descriptionAnnotation.value();
     }
+  }
 
+  private void initDefaultTabInfo(final V view) {
     DefaultTab defaultTabAnnotation = AnnotationUtils.getClassAnnotation(view, DefaultTab.class);
     if (defaultTabAnnotation != null) {
       if (defaultTabAnnotation.metrics().length == 0) {
@@ -86,30 +118,41 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
         defaultForMetrics = defaultTabAnnotation.metrics();
       }
     }
+  }
 
-    Description descriptionAnnotation = AnnotationUtils.getClassAnnotation(view, Description.class);
-    if (descriptionAnnotation != null) {
-      description = descriptionAnnotation.value();
+  private void initResourceLanguage(final V view) {
+    ResourceLanguage languageAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceLanguage.class);
+    if (languageAnnotation != null) {
+      resourceLanguages = languageAnnotation.value();
     }
+  }
 
-    WidgetProperties propAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetProperties.class);
-    if (propAnnotation != null) {
-      for (WidgetProperty property : propAnnotation.value()) {
-        widgetPropertiesByKey.put(property.key(), property);
-      }
+  private void initResourceQualifier(final V view) {
+    ResourceQualifier qualifierAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceQualifier.class);
+    if (qualifierAnnotation != null) {
+      resourceQualifiers = qualifierAnnotation.value();
     }
+  }
 
-    WidgetCategory categAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetCategory.class);
-    if (categAnnotation != null) {
-      widgetCategories = categAnnotation.value();
+  private void initResourceScope(final V view) {
+    ResourceScope scopeAnnotation = AnnotationUtils.getClassAnnotation(view, ResourceScope.class);
+    if (scopeAnnotation != null) {
+      resourceScopes = scopeAnnotation.value();
     }
+  }
 
-    WidgetLayout layoutAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetLayout.class);
-    if (layoutAnnotation != null) {
-      widgetLayout = layoutAnnotation.value();
+  private void initSections(final V view) {
+    NavigationSection sectionAnnotation = AnnotationUtils.getClassAnnotation(view, NavigationSection.class);
+    if (sectionAnnotation != null) {
+      sections = sectionAnnotation.value();
     }
+  }
 
-    isWidget = (view instanceof Widget);
+  private void initUserRoles(final V view) {
+    UserRole userRoleAnnotation = AnnotationUtils.getClassAnnotation(view, UserRole.class);
+    if (userRoleAnnotation != null) {
+      userRoles = userRoleAnnotation.value();
+    }
   }
 
   public V getTarget() {
@@ -171,6 +214,24 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
   public boolean supportsMetric(String metricKey) {
     return ArrayUtils.contains(defaultForMetrics, metricKey);
   }
+  
+  public boolean acceptsAvailableMeasures(String[] availableMeasures) {
+    for (String mandatoryMeasure : mandatoryMeasures) {
+      if (!ArrayUtils.contains(availableMeasures, mandatoryMeasure)) {
+        return false;
+      }
+    }
+    if (needOneOfMeasures.length == 0) {
+      return true;
+    } else {
+      for (String neededMeasure : needOneOfMeasures) {
+        if (ArrayUtils.contains(availableMeasures, neededMeasure)) {
+          return true;
+        }
+      }
+      return false;
+    }
+  }
 
   public boolean isWidget() {
     return isWidget;
@@ -203,7 +264,6 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
     return getId().hashCode();
   }
 
-
   @Override
   public boolean equals(Object obj) {
     if (obj == null) {
@@ -217,29 +277,29 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
     }
     ViewProxy rhs = (ViewProxy) obj;
     return new EqualsBuilder()
-      .append(getId(), rhs.getId())
-      .isEquals();
+        .append(getId(), rhs.getId())
+        .isEquals();
   }
 
   @Override
   public String toString() {
     return new ToStringBuilder(this)
-      .append("id", view.getId())
-      .append("sections", sections)
-      .append("userRoles", userRoles)
-      .append("scopes", resourceScopes)
-      .append("qualifiers", resourceQualifiers)
-      .append("languages", resourceLanguages)
-      .append("metrics", defaultForMetrics)
-      .toString();
+        .append("id", view.getId())
+        .append("sections", sections)
+        .append("userRoles", userRoles)
+        .append("scopes", resourceScopes)
+        .append("qualifiers", resourceQualifiers)
+        .append("languages", resourceLanguages)
+        .append("metrics", defaultForMetrics)
+        .toString();
 
   }
 
   public int compareTo(ViewProxy other) {
     return new CompareToBuilder()
-      .append(getTitle(), other.getTitle())
-      .append(getId(), other.getId())
-      .toComparison();
+        .append(getTitle(), other.getTitle())
+        .append(getId(), other.getId())
+        .toComparison();
 
   }
-}
\ No newline at end of file
+}
index 4e95904d52942ed8348691f7724e66fc45fb82b9..305daa0a471b6696fac7ccd88945f3a151857fcd 100644 (file)
  */
 package org.sonar.server.ui;
 
-import com.google.common.collect.Lists;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
 import org.apache.commons.lang.ArrayUtils;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.web.Page;
 import org.sonar.api.web.View;
 import org.sonar.api.web.Widget;
 
-import java.util.*;
+import com.google.common.collect.Lists;
 
 public class Views implements ServerComponent {
 
@@ -66,23 +71,23 @@ public class Views implements ServerComponent {
   }
 
   public List<ViewProxy<Page>> getPages(String section) {
-    return getPages(section, null, null, null);
+    return getPages(section, null, null, null, null);
   }
 
-  public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage) {
+  public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures) {
     List<ViewProxy<Page>> result = Lists.newArrayList();
     for (ViewProxy<Page> proxy : pages) {
-      if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage)) {
+      if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage, availableMeasures)) {
         result.add(proxy);
       }
     }
     return result;
   }
 
-  public List<ViewProxy<Page>> getPagesForMetric(String section, String resourceScope, String resourceQualifier, String resourceLanguage, String metric) {
+  public List<ViewProxy<Page>> getPagesForMetric(String section, String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures, String metric) {
     List<ViewProxy<Page>> result = Lists.newArrayList();
     for (ViewProxy<Page> proxy : pages) {
-      if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage) && proxy.supportsMetric(metric)) {
+      if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage, availableMeasures) && proxy.supportsMetric(metric)) {
         result.add(proxy);
       }
     }
@@ -93,10 +98,10 @@ public class Views implements ServerComponent {
     return widgetsPerId.get(id);
   }
 
-  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage) {
+  public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures) {
     List<ViewProxy<Widget>> result = Lists.newArrayList();
     for (ViewProxy<Widget> proxy : widgets) {
-      if (accept(proxy, null, resourceScope, resourceQualifier, resourceLanguage)) {
+      if (accept(proxy, null, resourceScope, resourceQualifier, resourceLanguage, availableMeasures)) {
         result.add(proxy);
       }
     }
@@ -107,11 +112,12 @@ public class Views implements ServerComponent {
     return Lists.newArrayList(widgets);
   }
 
-  private static boolean accept(ViewProxy proxy, String section, String resourceScope, String resourceQualifier, String resourceLanguage) {
+  protected static boolean accept(ViewProxy proxy, String section, String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures) {
     return acceptNavigationSection(proxy, section)
         && acceptResourceScope(proxy, resourceScope)
         && acceptResourceQualifier(proxy, resourceQualifier)
-        && acceptResourceLanguage(proxy, resourceLanguage);
+        && acceptResourceLanguage(proxy, resourceLanguage)
+        && acceptAvailableMeasures(proxy, availableMeasures);
   }
 
   protected static boolean acceptResourceLanguage(ViewProxy proxy, String resourceLanguage) {
@@ -129,4 +135,8 @@ public class Views implements ServerComponent {
   protected static boolean acceptNavigationSection(ViewProxy proxy, String section) {
     return proxy.isWidget() || section == null || ArrayUtils.contains(proxy.getSections(), section);
   }
+
+  protected static boolean acceptAvailableMeasures(ViewProxy proxy, String[] availableMeasures) {
+    return availableMeasures == null || proxy.acceptsAvailableMeasures(availableMeasures);
+  }
 }
index ad1ce1fa10d5765157652d1355659f1dc214cc8e..674d65090761fdcb7f082d0471cff5cbfad649c7 100644 (file)
@@ -35,9 +35,9 @@ class DashboardController < ApplicationController
       end
     else
       # display the layout of the parent, usually the directory, but display the file viewers
-      if @resource.last_snapshot
+      if @snapshot
         @file = @resource
-        @project = @resource.last_snapshot.parent.project
+        @project = @snapshot.parent.project
         render :action => 'no_dashboard'
       else
         redirect_to home_path
@@ -186,7 +186,7 @@ class DashboardController < ApplicationController
 
   def load_authorized_widget_definitions
     if @resource
-      @authorized_widget_definitions = java_facade.getWidgets(@resource.scope, @resource.qualifier, @resource.language)
+      @authorized_widget_definitions = java_facade.getWidgets(@resource.scope, @resource.qualifier, @resource.language, @snapshot.available_measures)
       @authorized_widget_definitions=@authorized_widget_definitions.select do |widget|
         authorized=widget.getUserRoles().size==0
         unless authorized
index 848e046f37196df76ce8d04b0dac02e4860be722..feb4f8e64eb7c4bcfda41b26c1e1fbb42154becb 100644 (file)
@@ -173,7 +173,7 @@ class DrilldownController < ApplicationController
 
   def display_metric_viewers?(resource, metric_key)
     return true if resource.file?
-    java_facade.getResourceTabsForMetric(resource.scope, resource.qualifier, resource.language, metric_key).each do |tab|
+    java_facade.getResourceTabsForMetric(resource.scope, resource.qualifier, resource.language, resource.last_snapshot.available_measures, metric_key).each do |tab|
       tab.getUserRoles().each do |role|
         if has_role?(role, resource)
           return true
index 9c5b1cfcfc2e00d2e4489f0090ccc1d6fa41cd6c..bf970cf2a9676bf658e55d57936106710f13c3f3 100644 (file)
@@ -113,7 +113,7 @@ class ResourceController < ApplicationController
 
   def load_extensions
     @extensions=[]
-    java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language).each do |tab|
+    java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language, @snapshot.available_measures).each do |tab|
       if tab.getUserRoles().empty?
         @extensions<<tab
       else
index d600cf6ef3ca25f365d2cf53f6e122671913416c..6d7f8b6e25c415c5f689dc273602d122f81fa47d 100644 (file)
@@ -248,6 +248,16 @@ class Snapshot < ActiveRecord::Base
     project_snapshot.send "period#{period_index}_date"
   end
 
+  # IMPORTANT: this is method must used only to pass arguments to the java_facade, as it returns
+  # an array of java.lang.String objects.
+  # It is used to know which views (page, tab, widget, ...) to display on for a given snapshot
+  def available_measures
+    if @available_measures.nil?
+      @available_measures = metrics.map {|m| m.name}.to_java(java.lang.String)
+    end
+    @available_measures
+  end
+
   private
 
   def measures_hash
index ab826232405a28f23de2e561f48cfc31fbb3a44b..e7bc7ca6d6aaf531f9aa90985216230fb77ca730 100644 (file)
@@ -39,7 +39,7 @@
             <li class="<%= 'selected' if controller.controller_path=='dependencies' -%>">
               <a href="<%= ApplicationController.root_context -%>/dependencies/index"><%= message('dependencies.page') -%></a></li>
 
-            <% controller.java_facade.getPages(Navigation::SECTION_HOME, nil, nil, nil).each do |page|
+            <% controller.java_facade.getPages(Navigation::SECTION_HOME, nil, nil, nil, nil).each do |page|
               selected=request.request_uri.include?("/plugins/home/#{page.getId()}") %>
               <li class="<%= 'selected' if selected -%>">
                 <a href="<%= ApplicationController.root_context -%>/plugins/home/<%= page.getId() -%>"><%= message(page.getId() + '.page', :default => page.getTitle()) -%></a></li>
@@ -57,7 +57,7 @@
               <a href="<%= ApplicationController.root_context -%>/drilldown/violations/<%= @project.id -%><%= "?"+period_param if period_param -%>"><%= message('violations_drilldown.page') -%></a></li>
             <li class="<%= 'selected' if request.request_uri.include?('/cloud/index') -%>">
               <a href="<%= ApplicationController.root_context -%>/cloud/index/<%= @project.id -%>"><%= message('clouds.page') -%></a></li>
-            <% controller.java_facade.getPages(Navigation::SECTION_RESOURCE, @project.scope, @project.qualifier, @project.language).each do |page| %>
+            <% controller.java_facade.getPages(Navigation::SECTION_RESOURCE, @project.scope, @project.qualifier, @project.language, @project.last_snapshot.available_measures).each do |page| %>
               <li class="<%= 'selected' if request.request_uri.include?("page=#{page.getId()}") -%>">
                 <a href="<%= ApplicationController.root_context -%>/plugins/resource/<%= @project.id -%>?page=<%= page.getId() -%>"><%= message(page.getId() + '.page', :default => page.getTitle()) %></a>
               </li>
                 <a href="<%= ApplicationController.root_context -%>/admin_filters/index"><%= message('default_filters.page') -%></a></li>
               <li class="<%= 'selected' if controller.controller_path=='admin_dashboards' -%>">
                 <a href="<%= ApplicationController.root_context -%>/admin_dashboards/index"><%= message('default_dashboards.page') -%></a></li>
-              <% controller.java_facade.getPages(Navigation::SECTION_CONFIGURATION, nil, nil, nil).each do |page| %>
+              <% controller.java_facade.getPages(Navigation::SECTION_CONFIGURATION, nil, nil, nil, nil).each do |page| %>
                 <li class="<%= 'selected' if request.request_uri.include?("plugins/configuration/#{page.getId()}") -%>">
                   <a href="<%= ApplicationController.root_context -%>/plugins/configuration/<%= page.getId() -%>"><%= message(page.getId() + '.page', :default => page.getTitle()) %></a>
                 </li>
index 460832cc7d5a9d2f65f679c408ef05c3af4e97c4..c2ae3c9d7edfd915c1f239c0a0789ab39f6bb0a6 100644 (file)
  */
 package org.sonar.server.ui;
 
-import org.junit.Test;
-import org.sonar.api.web.*;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.Matchers.lessThan;
 import static org.hamcrest.number.OrderingComparisons.greaterThan;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertThat;
 
+import org.junit.Test;
+import org.sonar.api.web.DefaultTab;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.RequiredMeasures;
+import org.sonar.api.web.UserRole;
+import org.sonar.api.web.View;
+import org.sonar.api.web.Widget;
+import org.sonar.api.web.WidgetProperties;
+import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertyType;
+
 public class ViewProxyTest {
 
   @Test
@@ -52,8 +60,8 @@ public class ViewProxyTest {
     ViewProxy proxy = new ViewProxy(view);
 
     assertThat(proxy.getTarget(), is(view));
-    assertArrayEquals(proxy.getSections(), new String[]{NavigationSection.RESOURCE});
-    assertArrayEquals(proxy.getUserRoles(), new String[]{UserRole.ADMIN});
+    assertArrayEquals(proxy.getSections(), new String[] {NavigationSection.RESOURCE});
+    assertArrayEquals(proxy.getUserRoles(), new String[] {UserRole.ADMIN});
   }
 
   @Test
@@ -68,11 +76,10 @@ public class ViewProxyTest {
     ViewProxy proxy = new ViewProxy(view);
 
     assertThat(proxy.getTarget(), is(view));
-    assertArrayEquals(proxy.getSections(), new String[]{NavigationSection.HOME});
+    assertArrayEquals(proxy.getSections(), new String[] {NavigationSection.HOME});
     assertThat(proxy.getUserRoles().length, org.hamcrest.Matchers.is(0));
   }
 
-
   @Test
   public void isDefaultTab() {
     @DefaultTab
@@ -112,7 +119,7 @@ public class ViewProxyTest {
     ViewProxy proxy = new ViewProxy<MyView>(new MyView());
 
     assertThat(proxy.isDefaultTab(), is(false));
-    assertThat(proxy.getDefaultTabForMetrics(), is(new String[]{"ncloc", "coverage"}));
+    assertThat(proxy.getDefaultTabForMetrics(), is(new String[] {"ncloc", "coverage"}));
   }
 
   @Test
@@ -133,6 +140,65 @@ public class ViewProxyTest {
     ViewProxy proxy = new ViewProxy<Widget>(new WidgetWithOptionalProperties());
     assertThat(proxy.hasRequiredProperties(), is(false));
   }
+
+  @Test
+  public void shouldAcceptAvailableMeasuresForNoRequiredMeasures() throws Exception {
+    class MyView extends FakeView {
+      MyView() {
+        super("fake");
+      }
+    }
+    ViewProxy proxy = new ViewProxy<MyView>(new MyView());
+
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "ncloc", "coverage"}), is(true));
+  }
+
+  @Test
+  public void shouldAcceptAvailableMeasuresForMandatoryMeasures() throws Exception {
+    @RequiredMeasures(mandatory = {"lines", "ncloc"})
+    class MyView extends FakeView {
+      MyView() {
+        super("fake");
+      }
+    }
+    ViewProxy proxy = new ViewProxy<MyView>(new MyView());
+
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "ncloc", "coverage"}), is(true));
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "coverage"}), is(false));
+  }
+
+  @Test
+  public void shouldAcceptAvailableMeasuresForOneOfNeededMeasures() throws Exception {
+    @RequiredMeasures(oneOf = {"lines", "ncloc"})
+    class MyView extends FakeView {
+      MyView() {
+        super("fake");
+      }
+    }
+    ViewProxy proxy = new ViewProxy<MyView>(new MyView());
+
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "coverage"}), is(true));
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"complexity", "coverage"}), is(false));
+  }
+
+  @Test
+  public void shouldAcceptAvailableMeasuresForMandatoryAndOneOfNeededMeasures() throws Exception {
+    @RequiredMeasures(mandatory = {"lines", "ncloc"}, oneOf = {"duplications", "duplictated_blocks"})
+    class MyView extends FakeView {
+      MyView() {
+        super("fake");
+      }
+    }
+    ViewProxy proxy = new ViewProxy<MyView>(new MyView());
+
+    // ok, mandatory measures and 1 needed measure
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "ncloc", "coverage", "duplications"}), is(true));
+    // ko, one of the needed measures but not all of the mandatory ones
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "coverage", "duplications"}), is(false));
+    // ko, mandatory measures but no one of the needed measures
+    assertThat(proxy.acceptsAvailableMeasures(new String[] {"lines", "nloc", "coverage", "dsm"}), is(false));
+  }
+
 }
 
 class FakeView implements View {
index fa4bded9aa2d951f1e96fd775f4125e4f886be82..eb83b805941f608fa5a3519665641d703fcb13c9 100644 (file)
  */
 package org.sonar.server.ui;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
 import org.junit.Test;
 import org.sonar.api.resources.Java;
 import org.sonar.api.resources.Qualifiers;
@@ -28,14 +36,6 @@ import org.sonar.api.web.Page;
 import org.sonar.api.web.View;
 import org.sonar.api.web.Widget;
 
-import java.util.List;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 public class ViewsTest {
 
   private static FakeResourceViewer FAKE_TAB = new FakeResourceViewer();
@@ -75,15 +75,15 @@ public class ViewsTest {
   @Test
   public void getWidgets() {
     final Views views = new Views(VIEWS);
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, null);
     assertThat(widgets.size(), is(1));
     assertThat(widgets.get(0).getTarget(), is(FakeWidget.class));
   }
 
   @Test
   public void sortViewsByTitle() {
-    final Views views = new Views(new View[]{new FakeWidget("ccc", "ccc"), new FakeWidget("aaa", "aaa"), new FakeWidget("bbb", "bbb")});
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    final Views views = new Views(new View[] {new FakeWidget("ccc", "ccc"), new FakeWidget("aaa", "aaa"), new FakeWidget("bbb", "bbb")});
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, null);
     assertThat(widgets.size(), is(3));
     assertThat(widgets.get(0).getId(), is("aaa"));
     assertThat(widgets.get(1).getId(), is("bbb"));
@@ -92,8 +92,8 @@ public class ViewsTest {
 
   @Test
   public void prefixTitleByNumberToDisplayFirst() {
-    final Views views = new Views(new View[]{new FakeWidget("other", "Other"), new FakeWidget("1id", "1widget"), new FakeWidget("2id", "2widget")});
-    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null);
+    final Views views = new Views(new View[] {new FakeWidget("other", "Other"), new FakeWidget("1id", "1widget"), new FakeWidget("2id", "2widget")});
+    List<ViewProxy<Widget>> widgets = views.getWidgets(null, null, null, null);
     assertThat(widgets.size(), is(3));
     assertThat(widgets.get(0).getId(), is("1id"));
     assertThat(widgets.get(1).getId(), is("2id"));
@@ -103,7 +103,7 @@ public class ViewsTest {
   @Test
   public void acceptNavigationSection() {
     ViewProxy proxy = mock(ViewProxy.class);
-    when(proxy.getSections()).thenReturn(new String[]{NavigationSection.RESOURCE});
+    when(proxy.getSections()).thenReturn(new String[] {NavigationSection.RESOURCE});
     when(proxy.isWidget()).thenReturn(false);
 
     assertThat(Views.acceptNavigationSection(proxy, NavigationSection.RESOURCE), is(true));
@@ -112,6 +112,21 @@ public class ViewsTest {
     assertThat(Views.acceptNavigationSection(proxy, null), is(true));
   }
 
+  @Test
+  public void acceptAvailableMeasures() {
+    ViewProxy proxy = mock(ViewProxy.class);
+    when(proxy.acceptsAvailableMeasures(new String[] {"lines"})).thenReturn(true);
+    when(proxy.acceptsAvailableMeasures(new String[] {"ncloc"})).thenReturn(false);
+
+    assertThat(Views.acceptAvailableMeasures(proxy, null), is(true));
+    assertThat(Views.acceptAvailableMeasures(proxy, new String[] {"lines"}), is(true));
+    assertThat(Views.acceptAvailableMeasures(proxy, new String[] {"ncloc"}), is(false));
+
+    assertThat(Views.accept(proxy, null, null, null, null, null), is(true));
+    assertThat(Views.accept(proxy, null, null, null, null, new String[] {"lines"}), is(true));
+    assertThat(Views.accept(proxy, null, null, null, null, new String[] {"ncloc"}), is(false));
+  }
+
   @Test
   public void doNotCheckNavigationSectionOnWidgets() {
     ViewProxy proxy = mock(ViewProxy.class);
@@ -128,7 +143,7 @@ public class ViewsTest {
     ViewProxy proxy = mock(ViewProxy.class);
     assertThat(Views.acceptResourceLanguage(proxy, Java.KEY), is(true));
 
-    when(proxy.getResourceLanguages()).thenReturn(new String[]{"foo"});
+    when(proxy.getResourceLanguages()).thenReturn(new String[] {"foo"});
     assertThat(Views.acceptResourceLanguage(proxy, Java.KEY), is(false));
     assertThat(Views.acceptResourceLanguage(proxy, "foo"), is(true));
   }
@@ -138,7 +153,7 @@ public class ViewsTest {
     ViewProxy proxy = mock(ViewProxy.class);
     assertThat(Views.acceptResourceScope(proxy, Scopes.FILE), is(true));
 
-    when(proxy.getResourceScopes()).thenReturn(new String[]{Scopes.PROJECT, Scopes.FILE});
+    when(proxy.getResourceScopes()).thenReturn(new String[] {Scopes.PROJECT, Scopes.FILE});
     assertThat(Views.acceptResourceScope(proxy, Scopes.FILE), is(true));
     assertThat(Views.acceptResourceScope(proxy, Scopes.DIRECTORY), is(false));
   }
@@ -148,8 +163,8 @@ public class ViewsTest {
     ViewProxy proxy = mock(ViewProxy.class);
     assertThat(Views.acceptResourceQualifier(proxy, Scopes.FILE), is(true));
 
-    when(proxy.getResourceQualifiers()).thenReturn(new String[]{Qualifiers.CLASS, Qualifiers.FILE});
+    when(proxy.getResourceQualifiers()).thenReturn(new String[] {Qualifiers.CLASS, Qualifiers.FILE});
     assertThat(Views.acceptResourceQualifier(proxy, Qualifiers.FILE), is(true));
     assertThat(Views.acceptResourceQualifier(proxy, Qualifiers.PACKAGE), is(false));
   }
-}
\ No newline at end of file
+}