package org.intellij.sonar.sonarserver;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.CommonProxy;
import org.apache.commons.lang.StringUtils;
import org.intellij.sonar.persistence.SonarServerConfig;
import org.intellij.sonar.util.ProgressIndicatorUtil;
import org.sonar.wsclient.Host;
import org.sonar.wsclient.JdkUtils;
import org.sonar.wsclient.Sonar;
import org.sonar.wsclient.SonarClient;
import org.sonar.wsclient.base.Paging;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueQuery;
import org.sonar.wsclient.issue.Issues;
import org.sonar.wsclient.services.Resource;
import org.sonar.wsclient.services.ResourceQuery;
import org.sonar.wsclient.services.WSUtils;
public class SonarServer {
private static final Logger LOG = Logger.getInstance(SonarServer.class);
private static final int CONNECT_TIMEOUT_IN_MILLISECONDS = 60*1000;
private static final int READ_TIMEOUT_IN_MILLISECONDS = 60*1000;
private final SonarServerConfig mySonarServerConfig;
private final Sonar sonar;
private final SonarClient sonarClient;
private SonarServer(SonarServerConfig sonarServerConfigBean) {
this.mySonarServerConfig = sonarServerConfigBean;
this.sonar = createSonar();
this.sonarClient = createSonarClient(createHost());
}
public static SonarServer create(SonarServerConfig sonarServerConfigBean) {
return new SonarServer(sonarServerConfigBean);
}
private SonarClient createSonarClient(Host host) {
SonarClient.Builder builder = SonarClient.builder()
.readTimeoutMilliseconds(READ_TIMEOUT_IN_MILLISECONDS)
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_IN_MILLISECONDS)
.url(host.getHost())
.login(host.getUsername())
.password(host.getPassword());
Optional<Proxy> proxy = getIntelliJProxyFor(host);
if (proxy.isPresent()) {
InetSocketAddress address = (InetSocketAddress) proxy.get().address();
HttpConfigurable proxySettings = HttpConfigurable.getInstance();
builder.proxy(address.getHostName(), address.getPort());
if (proxySettings.PROXY_AUTHENTICATION) {
builder.proxyLogin(proxySettings.getProxyLogin()).proxyPassword(proxySettings.getPlainProxyPassword());
}
}
return builder.build();
}
private Optional<Proxy> getIntelliJProxyFor(Host server) {
List<Proxy> proxies;
try {
proxies = CommonProxy.getInstance().select(new URL(server.getHost()));
} catch (MalformedURLException e) {
LOG.error("Unable to configure proxy", e);
return Optional.empty();
}
for (Proxy proxy : proxies) {
if (proxy.type() == Proxy.Type.HTTP) {
return Optional.of(proxy);
}
}
return Optional.empty();
}
private Sonar createSonar() {
Sonar newSonar;
if (mySonarServerConfig.isAnonymous()) {
newSonar = createSonar(mySonarServerConfig.getHostUrl(), null, null);
} else {
mySonarServerConfig.loadPassword();
newSonar = createSonar(mySonarServerConfig.getHostUrl(), mySonarServerConfig.getUser(), mySonarServerConfig.getPassword());
mySonarServerConfig.clearPassword();
}
return newSonar;
}
private Host createHost() {
Host host;
final String safeHostUrl = getHostSafe(mySonarServerConfig.getHostUrl());
if (mySonarServerConfig.isAnonymous()) {
host = new Host(safeHostUrl);
} else {
mySonarServerConfig.loadPassword();
host = new Host(safeHostUrl, mySonarServerConfig.getUser(), mySonarServerConfig.getPassword());
mySonarServerConfig.clearPassword();
}
return host;
}
private Sonar createSonar(String host, String user, String password) {
String safeHost = getHostSafe(host);
return StringUtils.isEmpty(user) ? Sonar.create(safeHost) : Sonar.create(safeHost, user, password);
}
private String getHostSafe(String hostName) {
return StringUtils.removeEnd(hostName, "/");
}
public Rule getRule(String key) {
String queryResponse = sonarClient.get("/api/rules/show", "key", key);
WSUtils wsUtils = new JdkUtils();
Object json = wsUtils.getField(wsUtils.parse(queryResponse), "rule");
org.sonar.wsclient.rule.Rule wsRule = new org.sonar.wsclient.rule.Rule((Map) json);
Rule rule = new Rule(wsRule.key(), wsRule.name(), wsUtils.getString(json, "severity"),
wsUtils.getString(json, "lang"), wsUtils.getString(json, "langName"), wsUtils.getString(json, "htmlDesc"),
wsRule.description());
return rule;
}
public List<Resource> getAllProjectsAndModules() {
List<Resource> allResources = new LinkedList<Resource>();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
indicator.setText("Downloading SonarQube projects");
List<Resource> projects = getAllProjects(sonar);
projects = projects.stream().sorted(new ByResourceName()).collect(Collectors.toList());
if (null != projects) {
indicator.setText("Downloading SonarQube modules");
int i = 0;
for (Resource project : projects) {
if (indicator.isCanceled()) break;
i++;
indicator.setFraction(1.0 * i / projects.size());
indicator.setText2(project.getName());
allResources.add(project);
List<Resource> modules = getAllModules(sonar, project.getId());
modules = modules.stream().sorted(new ByResourceName()).collect(Collectors.toList());
if (null != modules) {
for (Resource module : modules) {
allResources.add(module);
}
}
}
}
return allResources;
}
public List<Resource> getAllProjects(Sonar sonar) {
ResourceQuery query = new ResourceQuery();
query.setQualifiers(Resource.QUALIFIER_PROJECT);
query.setTimeoutMilliseconds(READ_TIMEOUT_IN_MILLISECONDS);
return sonar.findAll(query);
}
public List<Resource> getAllModules(Sonar sonar, Integer projectResourceId) {
ResourceQuery query = new ResourceQuery(projectResourceId);
query.setDepth(-1);
query.setQualifiers(Resource.QUALIFIER_MODULE);
query.setTimeoutMilliseconds(READ_TIMEOUT_IN_MILLISECONDS);
return sonar.findAll(query);
}
public ImmutableList<Issue> getAllIssuesFor(String resourceKey) {
final ImmutableList.Builder<Issue> builder = ImmutableList.builder();
IssueQuery query = IssueQuery.create()
.componentRoots(resourceKey)
.resolved(false)
.pageSize(-1);
Issues issues = sonarClient.issueClient().find(query);
builder.addAll(issues.list());
Paging paging = issues.paging();
Integer pages = paging.pages();
Integer total = paging.total();
Integer pageSize = paging.pageSize();
if (pages == null) {
pages = total / pageSize + (total % pageSize > 0 ? 1 : 0);
}
for (int pageIndex = 2; pageIndex <= pages; pageIndex++) {
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator.isCanceled())
break;
final String pagesProgressMessage = String.format("%d / %d pages downloaded", pageIndex, pages);
ProgressIndicatorUtil.setText(progressIndicator, pagesProgressMessage);
ProgressIndicatorUtil.setFraction(progressIndicator, pageIndex * 1.0 / pages);
query = IssueQuery.create()
.componentRoots(resourceKey)
.resolved(false)
.pageSize(-1)
.pageIndex(pageIndex);
issues = sonarClient.issueClient().find(query);
builder.addAll(issues.list());
}
return builder.build();
}
private static class ByResourceName implements Comparator<Resource> {
@Override
public int compare(Resource resource, Resource resource2) {
return resource.getName().compareTo(resource2.getName());
}
}
}