From f8b922fc348a36388a252082365a5741f056bdf6 Mon Sep 17 00:00:00 2001 From: Stephane Gamard Date: Tue, 10 Jun 2014 18:56:52 +0200 Subject: [PATCH] SONAR-5329 - Added LogsWebService and Definition Medium Test --- .../java/org/sonar/server/log/LogService.java | 17 +++- .../org/sonar/server/log/ws/LogMapping.java | 42 ++++++++ .../sonar/server/log/ws/LogsWebService.java | 43 ++++++++ .../org/sonar/server/log/ws/SearchAction.java | 98 +++++++++++++++++++ .../server/platform/ServerComponents.java | 7 ++ .../log/ws/LogsWebServiceMediumTest.java | 67 +++++++++++++ 6 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/log/ws/LogMapping.java create mode 100644 sonar-server/src/main/java/org/sonar/server/log/ws/LogsWebService.java create mode 100644 sonar-server/src/main/java/org/sonar/server/log/ws/SearchAction.java create mode 100644 sonar-server/src/test/java/org/sonar/server/log/ws/LogsWebServiceMediumTest.java diff --git a/sonar-server/src/main/java/org/sonar/server/log/LogService.java b/sonar-server/src/main/java/org/sonar/server/log/LogService.java index 7ad3ba2f324..fdca3b85f9d 100644 --- a/sonar-server/src/main/java/org/sonar/server/log/LogService.java +++ b/sonar-server/src/main/java/org/sonar/server/log/LogService.java @@ -24,6 +24,11 @@ import org.sonar.core.log.Loggable; import org.sonar.core.log.db.LogDto; import org.sonar.core.persistence.DbSession; import org.sonar.server.db.DbClient; +import org.sonar.server.log.index.LogIndex; +import org.sonar.server.log.index.LogQuery; +import org.sonar.server.log.index.LogResult; +import org.sonar.server.search.IndexClient; +import org.sonar.server.search.QueryOptions; import org.sonar.server.user.UserSession; import java.util.List; @@ -37,9 +42,11 @@ import java.util.List; public class LogService { private final DbClient dbClient; + private final IndexClient indexClient; - public LogService(DbClient dbClient) { + public LogService(DbClient dbClient, IndexClient indexClient) { this.dbClient = dbClient; + this.indexClient = indexClient; } private String getAuthor() { @@ -71,4 +78,12 @@ public class LogService { this.save(session, LogDto.createFor(log) .setType(type)); } + + public LogQuery newLogQuery() { + return new LogQuery(); + } + + public LogResult search(LogQuery query, QueryOptions options) { + return indexClient.get(LogIndex.class).search(query, options); + } } diff --git a/sonar-server/src/main/java/org/sonar/server/log/ws/LogMapping.java b/sonar-server/src/main/java/org/sonar/server/log/ws/LogMapping.java new file mode 100644 index 00000000000..abbec40df76 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/log/ws/LogMapping.java @@ -0,0 +1,42 @@ +/* + * 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.log.ws; + +import org.sonar.api.resources.Languages; +import org.sonar.server.log.index.LogNormalizer; +import org.sonar.server.search.ws.BaseMapping; +import org.sonar.server.text.MacroInterpreter; + +/** + * Conversion between Log and WS JSON response + */ +public class LogMapping extends BaseMapping { + + + public LogMapping(Languages languages, MacroInterpreter macroInterpreter) { + super(); + addIndexStringField("key", LogNormalizer.LogFields.KEY.field()); + addIndexStringField("type", LogNormalizer.LogFields.TYPE.field()); + addIndexDatetimeField("createdAt", LogNormalizer.LogFields.DATE.field()); + addIndexStringField("userLogin", LogNormalizer.LogFields.AUTHOR.field()); + addIndexStringField("message", LogNormalizer.LogFields.MESSAGE.field()); + addIndexStringField("executionTime", LogNormalizer.LogFields.EXECUTION.field()); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/log/ws/LogsWebService.java b/sonar-server/src/main/java/org/sonar/server/log/ws/LogsWebService.java new file mode 100644 index 00000000000..9ce5123d1d9 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/log/ws/LogsWebService.java @@ -0,0 +1,43 @@ +/* + * 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.log.ws; + +import org.sonar.api.server.ws.WebService; + +public class LogsWebService implements WebService { + + public static final String API_ENDPOINT = "api/logs"; + + private final SearchAction search; + + public LogsWebService(SearchAction search) { + this.search = search; + } + + @Override + public void define(Context context) { + NewController controller = context + .createController(API_ENDPOINT) + .setDescription("Logs search and views"); + + search.define(controller); + controller.done(); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/log/ws/SearchAction.java b/sonar-server/src/main/java/org/sonar/server/log/ws/SearchAction.java new file mode 100644 index 00000000000..975369b7040 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/log/ws/SearchAction.java @@ -0,0 +1,98 @@ +/* + * 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.log.ws; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.RequestHandler; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.core.log.Log; +import org.sonar.server.log.LogService; +import org.sonar.server.log.index.LogDoc; +import org.sonar.server.log.index.LogQuery; +import org.sonar.server.log.index.LogResult; +import org.sonar.server.search.QueryOptions; +import org.sonar.server.search.ws.SearchOptions; + +/** + * @since 4.4 + */ +public class SearchAction implements RequestHandler { + + public static final String PARAM_TYPE = "type"; + + public static final String SEARCH_ACTION = "search"; + + private final LogService logService; + private final LogMapping mapping; + + public SearchAction(LogService logService, LogMapping mapping) { + this.logService = logService; + this.mapping = mapping; + } + + void define(WebService.NewController controller) { + WebService.NewAction action = controller + .createAction(SEARCH_ACTION) + .setDescription("Search for a logs") + .setSince("4.4") + .setHandler(this); + + // Other parameters + action.createParam(PARAM_TYPE) + .setDescription("Select types of log to search") + .setPossibleValues(Log.Type.values()) + .setDefaultValue(StringUtils.join(Log.Type.values(), ",")); + + // Generic search parameters + SearchOptions.defineFieldsParam(action, mapping.supportedFields()); + + SearchOptions.definePageParams(action); + } + + @Override + public void handle(Request request, Response response) { + LogQuery query = createLogQuery(logService.newLogQuery(), request); + SearchOptions searchOptions = SearchOptions.create(request); + QueryOptions queryOptions = mapping.newQueryOptions(searchOptions); + + LogResult results = logService.search(query, queryOptions); + + JsonWriter json = response.newJsonWriter().beginObject(); + searchOptions.writeStatistics(json, results); + writeLogs(results, json, searchOptions); + json.endObject().close(); + } + + public static LogQuery createLogQuery(LogQuery query, Request request) { + // query.setTypes(request.param(SearchOptions.PARAM_TEXT_QUERY)); + return query; + } + + private void writeLogs(LogResult result, JsonWriter json, SearchOptions options) { + json.name("logs").beginArray(); + for (Log log : result.getHits()) { + mapping.write((LogDoc) log, json, options); + } + json.endArray(); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 935eabdebc5..79d0a3cbed9 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -132,6 +132,8 @@ import org.sonar.server.log.LogService; import org.sonar.server.log.db.LogDao; import org.sonar.server.log.index.LogIndex; import org.sonar.server.log.index.LogNormalizer; +import org.sonar.server.log.ws.LogMapping; +import org.sonar.server.log.ws.LogsWebService; import org.sonar.server.measure.MeasureFilterEngine; import org.sonar.server.measure.MeasureFilterExecutor; import org.sonar.server.measure.MeasureFilterFactory; @@ -468,6 +470,11 @@ class ServerComponents { pico.addSingleton(ActiveRuleCompleter.class); pico.addSingleton(AppAction.class); + pico.addSingleton(LogsWebService.class); + pico.addSingleton(org.sonar.server.log.ws.SearchAction.class); + pico.addSingleton(LogMapping.class); + + // measure pico.addComponent(MeasuresDao.class, false); pico.addSingleton(MeasureFilterFactory.class); diff --git a/sonar-server/src/test/java/org/sonar/server/log/ws/LogsWebServiceMediumTest.java b/sonar-server/src/test/java/org/sonar/server/log/ws/LogsWebServiceMediumTest.java new file mode 100644 index 00000000000..214d8cec38f --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/log/ws/LogsWebServiceMediumTest.java @@ -0,0 +1,67 @@ +package org.sonar.server.log.ws; + +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.server.ws.WebService; +import org.sonar.core.log.Log; +import org.sonar.core.persistence.DbSession; +import org.sonar.server.db.DbClient; +import org.sonar.server.log.LogService; +import org.sonar.server.tester.ServerTester; +import org.sonar.server.user.MockUserSession; +import org.sonar.server.ws.WsTester; + +import static org.fest.assertions.Assertions.assertThat; + +public class LogsWebServiceMediumTest { + + @ClassRule + public static ServerTester tester = new ServerTester(); + + private LogsWebService ws; + private LogService service; + private DbSession session; + + + @Before + public void setUp() throws Exception { + tester.clearDbAndIndexes(); + ws = tester.get(LogsWebService.class); + service = tester.get(LogService.class); + session = tester.get(DbClient.class).openSession(false); + } + + @After + public void after() { + session.close(); + } + + @Test + public void define() throws Exception { + WebService.Context context = new WebService.Context(); + ws.define(context); + + WebService.Controller controller = context.controller(LogsWebService.API_ENDPOINT); + + assertThat(controller).isNotNull(); + assertThat(controller.actions()).hasSize(1); + assertThat(controller.action(SearchAction.SEARCH_ACTION)).isNotNull(); + } + + @Test + public void search_logs() throws Exception { + service.write(session, Log.Type.ACTIVE_RULE, "Hello World"); + session.commit(); + + MockUserSession.set(); + + // 1. List single Text log + WsTester.TestRequest request = tester.wsTester().newGetRequest(LogsWebService.API_ENDPOINT, SearchAction.SEARCH_ACTION); + WsTester.Result result = request.execute(); + System.out.println("result = " + result.outputAsString()); + } + + +} -- 2.39.5