]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6866 Handle format suffix like .protobuf in WS url
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 21 Sep 2015 14:56:29 +0000 (16:56 +0200)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 30 Sep 2015 14:27:12 +0000 (16:27 +0200)
server/sonar-server/src/main/java/org/sonar/server/util/ObjectUtils.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ws/ServletRequest.java
server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceEngine.java
server/sonar-server/src/test/java/org/sonar/server/ws/ServletRequestTest.java
server/sonar-server/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/util/ObjectUtils.java b/server/sonar-server/src/main/java/org/sonar/server/util/ObjectUtils.java
new file mode 100644 (file)
index 0000000..09b57e7
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.util;
+
+public class ObjectUtils {
+
+  /**
+   * Taken from http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/src-html/org/apache/commons/lang3/ObjectUtils.html#line.119
+   * <p>Returns the first value in the array which is not {@code null}.
+    * If all the values are {@code null} or the array is {@code null}
+    * or empty then {@code null} is returned.</p>
+    *
+    * <pre>
+    * ObjectUtils.firstNonNull(null, null)      = null
+    * ObjectUtils.firstNonNull(null, "")        = ""
+    * ObjectUtils.firstNonNull(null, null, "")  = ""
+    * ObjectUtils.firstNonNull(null, "zz")      = "zz"
+    * ObjectUtils.firstNonNull("abc", *)        = "abc"
+    * ObjectUtils.firstNonNull(null, "xyz", *)  = "xyz"
+    * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
+    * ObjectUtils.firstNonNull()                = null
+    * </pre>
+    *
+    * @param <T> the component type of the array
+    * @param values  the values to test, may be {@code null} or empty
+    * @return the first value from {@code values} which is not {@code null},
+    *  or {@code null} if there are no non-null values
+    * @since 3.0
+    */
+  public static <T> T firstNonNull(T... values) {
+    if (values != null) {
+      for (T val : values) {
+        if (val != null) {
+          return val;
+        }
+      }
+    }
+    return null;
+  }
+}
index a1aa8d2d39b3e86d9a115b0a70ce9382b248723c..6e637c2a6cf8ba8e7bef6b7ab809547d4f5255df 100644 (file)
  */
 package org.sonar.server.ws;
 
-import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import java.io.InputStream;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.servlet.http.HttpServletRequest;
 import org.jruby.RubyFile;
 import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.server.plugins.MimeTypes;
 
-import javax.servlet.http.HttpServletRequest;
-
-import java.io.InputStream;
-import java.util.Map;
+import static org.sonar.server.util.ObjectUtils.firstNonNull;
 
 public class ServletRequest extends ValidatingRequest {
 
   private final HttpServletRequest source;
   private final Map<String, Object> params;
+  private static final Map<String, String> SUPPORTED_FORMATS = ImmutableMap.of(
+    "JSON", MimeTypes.JSON,
+    "PROTOBUF", MimeTypes.PROTOBUF,
+    "TEXT", MimeTypes.TXT);
 
   public ServletRequest(HttpServletRequest source, Map<String, Object> params) {
     this.source = source;
@@ -45,7 +51,8 @@ public class ServletRequest extends ValidatingRequest {
 
   @Override
   public String getMediaType() {
-    return Objects.firstNonNull(source.getContentType(), "application/octet-stream");
+    String mediaTypeFromUrl = mediaTypeFromUrl(source.getRequestURI());
+    return firstNonNull(mediaTypeFromUrl, source.getContentType(), MimeTypes.DEFAULT);
   }
 
   @Override
@@ -83,4 +90,10 @@ public class ServletRequest extends ValidatingRequest {
     }
     return url.toString();
   }
+
+  @CheckForNull
+  private static String mediaTypeFromUrl(String url) {
+    String mediaType = url.substring(url.lastIndexOf('.') + 1);
+    return SUPPORTED_FORMATS.get(mediaType.toUpperCase());
+  }
 }
index be69cbb783e3c1a4e998ee614a9b305c9c8078ac..038de3a04dd6e96afed3cb2293d01b592e0f5f16 100644 (file)
@@ -19,6 +19,9 @@
  */
 package org.sonar.server.ws;
 
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
 import org.picocontainer.Startable;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.server.ServerSide;
@@ -33,10 +36,7 @@ import org.sonar.server.exceptions.ServerException;
 import org.sonar.server.plugins.MimeTypes;
 import org.sonar.server.user.UserSession;
 
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
+import static java.lang.String.format;
 import static org.sonar.server.ws.RequestVerifier.verifyRequest;
 
 /**
@@ -98,13 +98,16 @@ public class WebServiceEngine implements Startable {
   }
 
   private WebService.Action getAction(String controllerPath, String actionKey) {
+    String actionKeyWithoutFormatSuffix = actionKey.contains(".") ?
+      actionKey.substring(0, actionKey.lastIndexOf('.'))
+      : actionKey;
     WebService.Controller controller = context.controller(controllerPath);
     if (controller == null) {
-      throw new BadRequestException(String.format("Unknown web service: %s", controllerPath));
+      throw new BadRequestException(format("Unknown web service: %s", controllerPath));
     }
-    WebService.Action action = controller.action(actionKey);
+    WebService.Action action = controller.action(actionKeyWithoutFormatSuffix);
     if (action == null) {
-      throw new BadRequestException(String.format("Unknown action: %s/%s", controllerPath, actionKey));
+      throw new BadRequestException(format("Unknown action: %s/%s", controllerPath, actionKeyWithoutFormatSuffix));
     }
     return action;
   }
index 93d32b702fe7e53dd1559e786314e550693354a1..2df707593ff29905bc643607fac60d1679eef6ad 100644 (file)
 package org.sonar.server.ws;
 
 import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import javax.servlet.http.HttpServletRequest;
 import org.jruby.RubyFile;
 import org.junit.Test;
-
-import javax.servlet.http.HttpServletRequest;
-
-import java.util.Collections;
 import org.sonar.server.plugins.MimeTypes;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 public class ServletRequestTest {
 
@@ -46,6 +46,7 @@ public class ServletRequestTest {
   @Test
   public void getMediaType() throws Exception {
     when(source.getContentType()).thenReturn(MimeTypes.JSON);
+    when(source.getRequestURI()).thenReturn("/path/to/resource/search");
     ServletRequest request = new ServletRequest(source, Collections.<String, Object>emptyMap());
     assertThat(request.getMediaType()).isEqualTo(MimeTypes.JSON);
   }
@@ -53,12 +54,21 @@ public class ServletRequestTest {
   @Test
   public void default_media_type_is_octet_stream() throws Exception {
     ServletRequest request = new ServletRequest(source, Collections.<String, Object>emptyMap());
-    assertThat(request.getMediaType()).isEqualTo("application/octet-stream");
+    when(source.getRequestURI()).thenReturn("/path/to/resource/search");
+    assertThat(request.getMediaType()).isEqualTo(MimeTypes.DEFAULT);
+  }
+
+  @Test
+  public void media_type_taken_in_url_first() throws Exception {
+    ServletRequest request = new ServletRequest(source, Collections.<String, Object>emptyMap());
+    when(source.getContentType()).thenReturn(MimeTypes.JSON);
+    when(source.getRequestURI()).thenReturn("/path/to/resource/search.protobuf");
+    assertThat(request.getMediaType()).isEqualTo(MimeTypes.PROTOBUF);
   }
 
   @Test
   public void has_param_from_source() {
-    when(source.getParameterMap()).thenReturn(ImmutableMap.of("param", new String[]{"value"}));
+    when(source.getParameterMap()).thenReturn(ImmutableMap.of("param", new String[] {"value"}));
     ServletRequest request = new ServletRequest(source, Collections.<String, Object>emptyMap());
     assertThat(request.hasParam("param")).isTrue();
   }
index 1dc9fa46239ef990d5b3855d60ef0cd5c89fe0bf..801d68593623cb3a4436fe79f31014c55b834ff2 100644 (file)
@@ -48,55 +48,6 @@ import static org.mockito.Mockito.when;
 
 public class WebServiceEngineTest {
 
-  private static class SimpleRequest extends ValidatingRequest {
-    private final String method;
-    private Map<String, String> params = Maps.newHashMap();
-
-    private SimpleRequest(String method) {
-      this.method = method;
-    }
-
-    @Override
-    public String method() {
-      return method;
-    }
-
-    @Override
-    public String getMediaType() {
-      return MimeTypes.JSON;
-    }
-
-    @Override
-    public boolean hasParam(String key) {
-      return params.keySet().contains(key);
-    }
-
-    @Override
-    protected String readParam(String key) {
-      return params.get(key);
-    }
-
-    @Override
-    protected InputStream readInputStreamParam(String key) {
-      String param = readParam(key);
-
-      return param == null ? null : IOUtils.toInputStream(param);
-    }
-
-    public SimpleRequest setParams(Map<String, String> m) {
-      this.params = m;
-      return this;
-    }
-
-    public SimpleRequest setParam(String key, @Nullable String value) {
-      if (value != null) {
-        params.put(key, value);
-      }
-      return this;
-    }
-
-  }
-
   @Rule
   public UserSessionRule userSessionRule = UserSessionRule.standalone();
   I18n i18n = mock(I18n.class);
@@ -127,6 +78,15 @@ public class WebServiceEngineTest {
     assertThat(response.stream().outputAsString()).isEqualTo("good");
   }
 
+  @Test
+  public void execute_request_with_format_type() {
+    ValidatingRequest request = new SimpleRequest("GET");
+    ServletResponse response = new ServletResponse();
+    engine.execute(request, response, "api/system", "health.protobuf");
+
+    assertThat(response.stream().outputAsString()).isEqualTo("good");
+  }
+
   @Test
   public void no_content() {
     ValidatingRequest request = new SimpleRequest("GET");
@@ -305,6 +265,55 @@ public class WebServiceEngineTest {
     assertThat(response.getHeader(name)).isEqualTo(value);
   }
 
+  private static class SimpleRequest extends ValidatingRequest {
+    private final String method;
+    private Map<String, String> params = Maps.newHashMap();
+
+    private SimpleRequest(String method) {
+      this.method = method;
+    }
+
+    @Override
+    public String method() {
+      return method;
+    }
+
+    @Override
+    public String getMediaType() {
+      return MimeTypes.JSON;
+    }
+
+    @Override
+    public boolean hasParam(String key) {
+      return params.keySet().contains(key);
+    }
+
+    @Override
+    protected String readParam(String key) {
+      return params.get(key);
+    }
+
+    @Override
+    protected InputStream readInputStreamParam(String key) {
+      String param = readParam(key);
+
+      return param == null ? null : IOUtils.toInputStream(param);
+    }
+
+    public SimpleRequest setParams(Map<String, String> m) {
+      this.params = m;
+      return this;
+    }
+
+    public SimpleRequest setParam(String key, @Nullable String value) {
+      if (value != null) {
+        params.put(key, value);
+      }
+      return this;
+    }
+
+  }
+
   static class SystemWs implements WebService {
     @Override
     public void define(Context context) {
@@ -405,5 +414,6 @@ public class WebServiceEngineTest {
       });
       newController.done();
     }
+
   }
 }