]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4083 add java web service API for metrics
authorJulien Lancelot <julien.lancelot@gmail.com>
Thu, 4 Apr 2013 13:11:14 +0000 (15:11 +0200)
committerJulien Lancelot <julien.lancelot@gmail.com>
Thu, 4 Apr 2013 13:11:29 +0000 (15:11 +0200)
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/metrics_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/metric.rb
sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricCreateQuery.java [new file with mode: 0644]
sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricDeleteQuery.java [new file with mode: 0644]
sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricUpdateQuery.java [new file with mode: 0644]
sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricCreateQueryTest.java [new file with mode: 0644]
sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricDeleteQueryTest.java [new file with mode: 0644]
sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricUpdateQueryTest.java [new file with mode: 0644]

index 9c5e0357794136f32e721477d6a08c1a4252a190..b2873a28a0cf8d55f3299b7d178a16f9fd60ba33 100644 (file)
@@ -20,7 +20,7 @@
 
 require "json"
 
-class Api::MetricsController < Api::RestController
+class Api::MetricsController < Api::ApiController
 
   # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
   verify :method => :put, :only => [ :update ]
@@ -29,90 +29,98 @@ class Api::MetricsController < Api::RestController
 
   before_filter :admin_required, :only => [ :create, :update, :destroy ]
 
+  # GET /api/metrics
   def index
     metrics = Metric.all
-    rest_render(metrics)
+    respond_to do |format|
+      format.json { render :json => jsonp(metrics_to_json(metrics)) }
+      format.xml { render :xml => metrics_to_xml(metrics) }
+    end
   end
 
+  # GET /api/metrics/foo
   def show
     metric = Metric.by_key(params[:id])
     if !metric
-      rest_status_ko('Metric [' + params[:id] + '] does not exist', 404)
+      render_not_found('Metric [' + params[:id] + '] does not exist')
     else
-      rest_render([metric])
+      respond_to do |format|
+        format.json { render :json => jsonp(metrics_to_json(metric)) }
+        format.xml { render :xml => metrics_to_xml([metric]) }
+      end
     end
   end
 
+  # curl -u admin:admin -v -X POST http://localhost:9000/api/metrics/foo?name=bar&val_type=<type>[&description=<description>&domain=<domain>]
   def create
-    bad_request('Name is required') unless params[:name].present?
-    metric_name = params[:name].downcase.gsub(/\s/, '_')[0..59]
-    metric_id_as_text = params[:id].downcase.gsub(/\s/, '_')[0..59] if params[:id] && params[:id].to_i > 0
-
-    metric_test = Metric.first(:conditions => ['name=? OR id=?', metric_id_as_text, params[:id].to_i])
+    metric_test = Metric.first(:conditions => ['name=?', params[:id]])
 
     exist_and_is_disable = !metric_test.nil? && !metric_test.enabled?
     if exist_and_is_disable
       metric = metric_test
     else
       metric = Metric.new
-    end
-
-    begin
-      metric.attributes = params.merge({:name => metric_id_as_text, :short_name => metric_name})
-      if metric.short_name(false)
-        metric.name = metric.short_name(false) unless metric_id_as_text
-      end
-      metric.origin = Metric::ORIGIN_WS
-      metric.user_managed = true
-      metric.enabled = true
-      metric.save!
-      Metric.clear_cache
-      rest_status_ok
-    rescue
-      rest_status_ko(metric.errors.full_messages.join("."), 400)
+   end
+
+    metric.attributes = params.merge({:name => params[:id], :short_name => params[:name]})
+    metric.origin = Metric::ORIGIN_WS
+    metric.user_managed = true
+    metric.enabled = true
+    metric.save!
+    Metric.clear_cache
+
+    respond_to do |format|
+      format.json { render :json => jsonp(metrics_to_json(metric)) }
+      format.xml { render :xml => metrics_to_xml([metric]) }
     end
   end
 
+  # curl -u admin:admin -v -X PUT http://localhost:9000/api/metrics/foo?name=bar&val_type=<type>[&description=<description>&domain=<domain>]
   def update
-    metric = Metric.first(:conditions => ['(name=? OR id=?) AND enabled=? AND user_managed=?', params[:id], params[:id].to_i, true, true])
+    metric = Metric.first(:conditions => ['name=? AND enabled=? AND user_managed=?', params[:id], true, true])
     if metric
-      begin
-        metric.attributes = params.merge({:name => params[:id], :short_name => params[:name]})
-        metric.save!
-        Metric.clear_cache
-        rest_status_ok
-      rescue
-        rest_status_ko(metric.errors.full_messages.join("."), 400)
+      metric.attributes = params.merge({:name => params[:id], :short_name => params[:name]})
+      metric.save!
+      Metric.clear_cache
+
+      respond_to do |format|
+        format.json { render :json => jsonp(metrics_to_json(metric)) }
+        format.xml { render :xml => metrics_to_xml([metric]) }
       end
     else
-      rest_status_ko('Unable to update manual metric: '+ params[:id], 404)
+      render_not_found('Unable to update manual metric: '+ params[:id])
     end
   end
 
+  # curl -u admin:admin -v -X DELETE http://localhost:9000/api/metrics/foo
   def destroy
     metric = Metric.first(:conditions => ['(name=? OR id=?) AND enabled=? AND user_managed=?', params[:id], params[:id].to_i, true, true])
     if !metric
-      rest_status_ko('Unable to delete manual metric which does not exist: ' + params[:id], 404)
+      render_not_found('Unable to delete manual metric which does not exist: '+ params[:id])
     else
       metric.enabled = false
-      begin
-        metric.save!
-        Metric.clear_cache
-        rest_status_ok
-      rescue
-        rest_status_ko(metric.errors.full_messages.join("."), 400)
-      end
+      metric.save!
+      Metric.clear_cache
+      render_success('metric deleted')
     end
   end
 
 
   protected
 
-  def rest_to_json(metrics)
-    JSON(metrics.collect{|metric| metric.to_hash_json(params)})
+  def metrics_to_json(metrics)
+    json = []
+    metrics.each do |m|
+      json<<rest_to_json(m)
+    end
+    json
+  end
+
+  def metrics_to_json(metric)
+    metric.to_hash_json
   end
 
-  def rest_to_xml(metrics)
+  def metrics_to_xml(metrics)
     xml = Builder::XmlMarkup.new(:indent => 0)
     xml.instruct! 
     xml.metrics do
index 9559cbfdadb884965b39564f3cc1fa8dcf805e7c..a6b35aa1ad2f154dafcb2e8cf0b9341c57d55807 100644 (file)
@@ -44,7 +44,8 @@ class Metric < ActiveRecord::Base
   I18N_DOMAIN_CACHE_KEY='i18n_domains'
   I18N_SHORT_NAME_CACHE_KEY='i18n_metric_short_names'
 
-  validates_length_of       :name, :within => 1..64
+  validates_format_of       :name,   :with => /\A\w+\z/
+  validates_length_of       :name,   :within => 1..64
   validates_uniqueness_of   :name
   validates_length_of       :short_name, :within => 1..64
   validates_inclusion_of    :val_type, :in => [VALUE_TYPE_INT,VALUE_TYPE_BOOLEAN,VALUE_TYPE_FLOAT,VALUE_TYPE_PERCENT,VALUE_TYPE_STRING,VALUE_TYPE_MILLISEC,VALUE_TYPE_LEVEL, VALUE_TYPE_DATA, VALUE_TYPE_DISTRIB], :message => "wrong value type"
@@ -305,6 +306,15 @@ class Metric < ActiveRecord::Base
     origin==ORIGIN_GUI
   end
 
+  HUMANIZED_ATTRIBUTES = {
+      :name => "key",
+      :short_name => "name",
+  }
+
+  def self.human_attribute_name(attr)
+    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
+  end
+
   # METRIC DEFINITIONS
   # WARNING if you edit this file do not forget to also change sonar-commons/src/main/java/ch/hortis/sonar/model/Metrics.java
   LINES = 'lines'
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricCreateQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricCreateQuery.java
new file mode 100644 (file)
index 0000000..b40d0ed
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.wsclient.services;
+
+/**
+ * @since 3.6
+ */
+public class MetricCreateQuery extends CreateQuery<Metric>  {
+
+  private String key;
+  private String name;
+  private String description;
+  private String domain;
+  private String type;
+
+  public static MetricCreateQuery create(String metricKey) {
+    return new MetricCreateQuery(metricKey);
+  }
+
+  private MetricCreateQuery(String key) {
+    this.key = key;
+  }
+
+  public MetricCreateQuery setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public MetricCreateQuery setDescription(String description) {
+    this.description = description;
+    return this;
+  }
+
+  public MetricCreateQuery setDomain(String domain) {
+    this.domain = domain;
+    return this;
+  }
+
+  public MetricCreateQuery setType(String type) {
+    this.type = type;
+    return this;
+  }
+
+  @Override
+  public String getUrl() {
+    StringBuilder url = new StringBuilder();
+    url.append(MetricQuery.BASE_URL);
+    url.append("/").append(encode(key));
+    url.append('?');
+    appendUrlParameter(url, "name", name);
+    appendUrlParameter(url, "description", description);
+    appendUrlParameter(url, "domain", domain);
+    appendUrlParameter(url, "val_type", type);
+    return url.toString();
+  }
+
+  @Override
+  public Class<Metric> getModelClass() {
+    return Metric.class;
+  }
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricDeleteQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricDeleteQuery.java
new file mode 100644 (file)
index 0000000..c736629
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.wsclient.services;
+
+/**
+ * @since 3.6
+ */
+public class MetricDeleteQuery extends DeleteQuery {
+
+  private String key;
+
+  public static MetricDeleteQuery delete(String key){
+    return new MetricDeleteQuery(key);
+  }
+
+  private MetricDeleteQuery(String key) {
+    this.key = key;
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public MetricDeleteQuery setKey(String key) {
+    this.key = key;
+    return this;
+  }
+
+  @Override
+  public String getUrl() {
+    StringBuilder url = new StringBuilder();
+    url.append(MetricQuery.BASE_URL);
+    url.append("/").append(encode(key));
+    return url.toString();
+  }
+}
diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricUpdateQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/services/MetricUpdateQuery.java
new file mode 100644 (file)
index 0000000..b0596d9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.wsclient.services;
+
+/**
+ * @since 2.6
+ */
+public class MetricUpdateQuery extends UpdateQuery<Metric> {
+
+  private String key;
+  private String name;
+  private String description;
+  private String domain;
+  private String type;
+
+  public static MetricUpdateQuery update(String key){
+    return new MetricUpdateQuery(key);
+  }
+
+  private MetricUpdateQuery(String key) {
+    this.key = key;
+  }
+
+  public MetricUpdateQuery setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public MetricUpdateQuery setDescription(String description) {
+    this.description = description;
+    return this;
+  }
+
+  public MetricUpdateQuery setDomain(String domain) {
+    this.domain = domain;
+    return this;
+  }
+
+  public MetricUpdateQuery setType(String type) {
+    this.type = type;
+    return this;
+  }
+
+  @Override
+  public String getUrl() {
+    StringBuilder url = new StringBuilder();
+    url.append(MetricQuery.BASE_URL);
+    url.append("/").append(encode(key));
+    url.append('?');
+    appendUrlParameter(url, "name", name);
+    appendUrlParameter(url, "description", description);
+    appendUrlParameter(url, "domain", domain);
+    appendUrlParameter(url, "val_type", type);
+    return url.toString();
+  }
+
+  /**
+   * Property {@link #description} transmitted through request body as content may exceed URL size allowed by the server.
+   */
+  @Override
+  public String getBody() {
+    return description;
+  }
+
+  @Override
+  public Class<Metric> getModelClass() {
+    return Metric.class;
+  }
+}
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricCreateQueryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricCreateQueryTest.java
new file mode 100644 (file)
index 0000000..a43051c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.wsclient.services;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MetricCreateQueryTest extends QueryTestCase {
+
+  @Test
+  public void should_create() {
+    MetricCreateQuery query = MetricCreateQuery.create("key").setName("name").setDescription("description").setDomain("domain").setType("type");
+    assertThat(query.getUrl()).isEqualTo("/api/metrics/key?name=name&description=description&domain=domain&val_type=type&");
+    assertThat(query.getModelClass().getName()).isEqualTo(Metric.class.getName());
+  }
+
+}
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricDeleteQueryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricDeleteQueryTest.java
new file mode 100644 (file)
index 0000000..8509e78
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.wsclient.services;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MetricDeleteQueryTest extends QueryTestCase {
+
+  @Test
+  public void should_delete() {
+    MetricDeleteQuery query = MetricDeleteQuery.delete("key");
+    assertThat(query.getUrl()).isEqualTo("/api/metrics/key");
+  }
+}
diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricUpdateQueryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/services/MetricUpdateQueryTest.java
new file mode 100644 (file)
index 0000000..fe35a04
--- /dev/null
@@ -0,0 +1,17 @@
+package org.sonar.wsclient.services;
+
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class MetricUpdateQueryTest extends QueryTestCase {
+
+  @Test
+  public void should_update() {
+    MetricUpdateQuery query = MetricUpdateQuery.update("key").setName("name").setDescription("description").setDomain("domain").setType("type");
+    assertThat(query.getUrl()).isEqualTo("/api/metrics/key?name=name&description=description&domain=domain&val_type=type&");
+    assertThat(query.getBody()).isEqualTo("description");
+    assertThat(query.getModelClass().getName()).isEqualTo(Metric.class.getName());
+  }
+
+}