aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-pushapi
diff options
context:
space:
mode:
authorPierre <pierre.guillot@sonarsource.com>2022-02-03 12:10:18 +0100
committersonartech <sonartech@sonarsource.com>2022-02-18 15:48:04 +0000
commit0c8ff1bac53c2dfa89e7be014b64b411f24434c0 (patch)
treebcad0a2d4daafe106d82f7765be71fec146eb879 /server/sonar-webserver-pushapi
parent24cd8d71c3b6df3f33f1ff0232c83bbb0a9fc060 (diff)
downloadsonarqube-0c8ff1bac53c2dfa89e7be014b64b411f24434c0.tar.gz
sonarqube-0c8ff1bac53c2dfa89e7be014b64b411f24434c0.zip
SONAR-15919 add ruleset changes
Diffstat (limited to 'server/sonar-webserver-pushapi')
-rw-r--r--server/sonar-webserver-pushapi/build.gradle1
-rw-r--r--server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/ServerPushClient.java17
-rw-r--r--server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClient.java8
-rw-r--r--server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistry.java88
-rw-r--r--server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintPushAction.java4
-rw-r--r--server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistryTest.java3
6 files changed, 117 insertions, 4 deletions
diff --git a/server/sonar-webserver-pushapi/build.gradle b/server/sonar-webserver-pushapi/build.gradle
index a2c94714bd0..f3f66fea494 100644
--- a/server/sonar-webserver-pushapi/build.gradle
+++ b/server/sonar-webserver-pushapi/build.gradle
@@ -8,6 +8,7 @@ dependencies {
compile 'javax.servlet:javax.servlet-api'
compile project(':server:sonar-webserver-auth')
compile project(':server:sonar-webserver-ws')
+ compile project(':server:sonar-webserver-webapi')
testCompile 'junit:junit'
testCompile 'org.assertj:assertj-core'
diff --git a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/ServerPushClient.java b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/ServerPushClient.java
index 4904b9e7cd1..cc0d3d7f0c7 100644
--- a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/ServerPushClient.java
+++ b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/ServerPushClient.java
@@ -20,6 +20,7 @@
package org.sonar.server.pushapi;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -34,6 +35,17 @@ public abstract class ServerPushClient {
private static final Logger LOG = Loggers.get(ServerPushClient.class);
private static final int DEFAULT_HEARTBEAT_PERIOD = 60;
+
+
+
+ private static final byte[] CRLF = new byte[] {'\r', '\n'};
+ private static final byte[] DATA_END = new byte[] {'\n', '\n'};
+ private static final byte[] DATA_FIELD = "data: ".getBytes(StandardCharsets.UTF_8);
+
+
+
+
+
protected final AsyncContext asyncContext;
private final ScheduledExecutorService executorService;
@@ -50,6 +62,11 @@ public abstract class ServerPushClient {
startedHeartbeat = executorService.schedule(heartbeatTask, DEFAULT_HEARTBEAT_PERIOD, TimeUnit.SECONDS);
}
+ public void writeAndFlush(String payload) throws IOException {
+ output().write(payload.getBytes(StandardCharsets.UTF_8));
+ flush();
+ }
+
public void writeAndFlush(char character) {
write(character);
flush();
diff --git a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClient.java b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClient.java
index b022cbcb25d..93512a974ec 100644
--- a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClient.java
+++ b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClient.java
@@ -39,6 +39,14 @@ public class SonarLintClient extends ServerPushClient {
this.languages = languages;
}
+ public Set<String> getLanguages() {
+ return languages;
+ }
+
+ public Set<String> getClientProjectKeys() {
+ return projectKeys;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistry.java b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistry.java
index e93bf5f9073..4b72f6de66d 100644
--- a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistry.java
+++ b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistry.java
@@ -19,25 +19,46 @@
*/
package org.sonar.server.pushapi.sonarlint;
+import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Predicate;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.ParamChange;
+import org.sonar.core.util.RuleActivationListener;
+import org.sonar.core.util.RuleChange;
+import org.sonar.core.util.RuleSetChangeEvent;
+import org.sonar.server.qualityprofile.RuleActivatorEventsDistributor;
+
+import static java.util.Arrays.asList;
@ServerSide
-public class SonarLintClientsRegistry {
+public class SonarLintClientsRegistry implements RuleActivationListener {
private static final Logger LOG = Loggers.get(SonarLintClientsRegistry.class);
+ private final RuleActivatorEventsDistributor ruleActivatorEventsDistributor;
+
+ public SonarLintClientsRegistry(RuleActivatorEventsDistributor ruleActivatorEventsDistributor) {
+ this.ruleActivatorEventsDistributor = ruleActivatorEventsDistributor;
+ }
+
+
private final List<SonarLintClient> clients = new CopyOnWriteArrayList<>();
public void registerClient(SonarLintClient sonarLintClient) {
clients.add(sonarLintClient);
sonarLintClient.scheduleHeartbeat();
sonarLintClient.addListener(new SonarLintClientEventsListener(sonarLintClient));
+ ruleActivatorEventsDistributor.subscribe(this);
+
LOG.debug("Registering new SonarLint client");
}
@@ -50,6 +71,71 @@ public class SonarLintClientsRegistry {
return clients.size();
}
+ @Override
+ public void listen(RuleSetChangeEvent ruleChangeEvent) {
+ LOG.info("Generating a RuleSetChangeEvent");
+ // TODO filter on languages here as well
+ broadcastMessage(ruleChangeEvent, f -> f.getClientProjectKeys().isEmpty() || !Collections.disjoint(f.getClientProjectKeys(), asList(ruleChangeEvent.getProjects())));
+ }
+
+
+ public void broadcastMessage(RuleSetChangeEvent message, Predicate<SonarLintClient> filter) {
+ String jsonString = getJSONString(message);
+ clients.stream().filter(filter).forEach(c -> {
+ try {
+ c.writeAndFlush(jsonString);
+ } catch (IOException e) {
+ LOG.error("Unable to send message to a client: " + e.getMessage());
+ }
+ });
+ }
+
+
+ public String getJSONString(RuleSetChangeEvent ruleSetChangeEvent) {
+ JSONObject result = new JSONObject();
+ result.put("event", ruleSetChangeEvent.getEvent());
+
+ JSONObject data = new JSONObject();
+ data.put("projects", ruleSetChangeEvent.getProjects());
+
+ JSONArray activatedRulesJson = new JSONArray();
+ for (RuleChange rule : ruleSetChangeEvent.getActivatedRules()) {
+ activatedRulesJson.put(toJson(rule));
+ }
+ data.put("activatedRules", activatedRulesJson);
+
+ JSONArray deactivatedRulesJson = new JSONArray();
+ for (RuleChange rule : ruleSetChangeEvent.getDeactivatedRules()) {
+ deactivatedRulesJson.put(toJson(rule));
+ }
+ data.put("deactivatedRules", deactivatedRulesJson);
+
+ result.put("data", data);
+ return result.toString();
+ }
+
+ private JSONObject toJson(RuleChange rule) {
+ JSONObject ruleJson = new JSONObject();
+ ruleJson.put("key", rule.getKey());
+ ruleJson.put("language", rule.getLanguage());
+ ruleJson.put("severity", rule.getSeverity());
+ ruleJson.put("templateKey", rule.getTemplateKey());
+
+ JSONArray params = new JSONArray();
+ for (ParamChange paramChange : rule.getParams()) {
+ params.put(toJson(paramChange));
+ }
+ ruleJson.put("params", params);
+ return ruleJson;
+ }
+
+ private JSONObject toJson(ParamChange paramChange) {
+ JSONObject param = new JSONObject();
+ param.put("key", paramChange.getKey());
+ param.put("value", paramChange.getValue());
+ return param;
+ }
+
class SonarLintClientEventsListener implements AsyncListener {
private final SonarLintClient client;
diff --git a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintPushAction.java b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintPushAction.java
index 5bcce895562..2c27c48cda1 100644
--- a/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintPushAction.java
+++ b/server/sonar-webserver-pushapi/src/main/java/org/sonar/server/pushapi/sonarlint/SonarLintPushAction.java
@@ -84,7 +84,7 @@ public class SonarLintPushAction extends ServerPushAction {
if (!isServerSideEventsRequest(servletRequest)) {
servletResponse.stream().setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
- return;
+ return; // TODO fixme this is not closing the connexion properly
}
setHeadersForResponse(servletResponse);
@@ -92,7 +92,7 @@ public class SonarLintPushAction extends ServerPushAction {
AsyncContext asyncContext = servletRequest.startAsync();
asyncContext.setTimeout(0);
- var sonarLintClient = new SonarLintClient(asyncContext, params.getProjectKeys(), params.getLanguages());
+ SonarLintClient sonarLintClient = new SonarLintClient(asyncContext, params.getProjectKeys(), params.getLanguages());
clientsRegistry.registerClient(sonarLintClient);
}
diff --git a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistryTest.java b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistryTest.java
index 450245c13c0..49076199685 100644
--- a/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistryTest.java
+++ b/server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/sonarlint/SonarLintClientsRegistryTest.java
@@ -23,6 +23,7 @@ import java.util.Set;
import javax.servlet.AsyncContext;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.server.qualityprofile.StandaloneRuleActivatorEventsDistributor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -39,7 +40,7 @@ public class SonarLintClientsRegistryTest {
@Before
public void before() {
- underTest = new SonarLintClientsRegistry();
+ underTest = new SonarLintClientsRegistry(mock(StandaloneRuleActivatorEventsDistributor.class));
}
@Test