package com.capitalone.dashboard.collector;
import com.capitalone.dashboard.model.*;
import com.capitalone.dashboard.repository.BaseCollectorRepository;
import com.capitalone.dashboard.repository.CodeQualityRepository;
import com.capitalone.dashboard.repository.ComponentRepository;
import com.capitalone.dashboard.repository.SonarCollectorRepository;
import com.capitalone.dashboard.repository.SonarProjectRepository;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public class SonarCollectorTask extends CollectorTask<SonarCollector> {
private static final Log LOG = LogFactory.getLog(SonarCollectorTask.class);
private final SonarCollectorRepository sonarCollectorRepository;
private final SonarProjectRepository sonarProjectRepository;
private final CodeQualityRepository codeQualityRepository;
private final SonarClient sonarClient;
private final SonarSettings sonarSettings;
private final ComponentRepository dbComponentRepository;
private final int CLEANUP_INTERVAL = 3600000;
@Autowired
public SonarCollectorTask(TaskScheduler taskScheduler,
SonarCollectorRepository sonarCollectorRepository,
SonarProjectRepository sonarProjectRepository,
CodeQualityRepository codeQualityRepository,
SonarSettings sonarSettings,
SonarClient sonarClient,
ComponentRepository dbComponentRepository) {
super(taskScheduler, "Sonar");
this.sonarCollectorRepository = sonarCollectorRepository;
this.sonarProjectRepository = sonarProjectRepository;
this.codeQualityRepository = codeQualityRepository;
this.sonarSettings = sonarSettings;
this.sonarClient = sonarClient;
this.dbComponentRepository = dbComponentRepository;
}
@Override
public SonarCollector getCollector() {
return SonarCollector.prototype(sonarSettings.getServers());
}
@Override
public BaseCollectorRepository<SonarCollector> getCollectorRepository() {
return sonarCollectorRepository;
}
@Override
public String getCron() {
return sonarSettings.getCron();
}
@Override
public void collect(SonarCollector collector) {
long start = System.currentTimeMillis();
// Clean up every hour
if ((start - collector.getLastExecuted()) > CLEANUP_INTERVAL) {
clean(collector);
}
for (String instanceUrl : collector.getSonarServers()) {
logInstanceBanner(instanceUrl);
List<SonarProject> projects = sonarClient.getProjects(instanceUrl);
int projSize = ((projects != null) ? projects.size() : 0);
log("Fetched projects " + projSize , start);
addNewProjects(projects, collector);
refreshData(enabledProjects(collector, instanceUrl));
log("Finished", start);
}
}
/**
* Clean up unused sonar collector items
*
* @param collector
* the {@link HudsonCollector}
*/
private void clean(SonarCollector collector) {
Set<ObjectId> uniqueIDs = new HashSet<ObjectId>();
for (com.capitalone.dashboard.model.Component comp : dbComponentRepository
.findAll()) {
if ((comp.getCollectorItems() != null)
&& !comp.getCollectorItems().isEmpty()) {
List<CollectorItem> itemList = comp.getCollectorItems().get(
CollectorType.CodeQuality);
if (itemList != null) {
for (CollectorItem ci : itemList) {
if ((ci != null) && (ci.getCollectorId().equals(collector.getId()))){
uniqueIDs.add(ci.getId());
}
}
}
}
}
List<SonarProject> jobList = new ArrayList<SonarProject>();
Set<ObjectId> udId = new HashSet<ObjectId>();
udId.add(collector.getId());
for (SonarProject job : sonarProjectRepository.findByCollectorIdIn(udId)) {
if (job != null) {
job.setEnabled(uniqueIDs.contains(job.getId()));
jobList.add(job);
}
}
sonarProjectRepository.save(jobList);
}
private void refreshData(List<SonarProject> sonarProjects) {
long start = System.currentTimeMillis();
int count = 0;
for (SonarProject project : sonarProjects) {
CodeQuality codeQuality = sonarClient.currentCodeQuality(project);
if ((codeQuality != null) && isNewQualityData(project, codeQuality)) {
codeQuality.setCollectorItemId(project.getId());
codeQualityRepository.save(codeQuality);
count++;
}
}
log("Updated", start, count);
}
private List<SonarProject> enabledProjects(SonarCollector collector, String instanceUrl) {
return sonarProjectRepository.findEnabledProjects(collector.getId(), instanceUrl);
}
private void addNewProjects(List<SonarProject> projects, SonarCollector collector) {
long start = System.currentTimeMillis();
int count = 0;
for (SonarProject project : projects) {
if (isNewProject(collector, project)) {
project.setCollectorId(collector.getId());
project.setEnabled(false);
project.setDescription(project.getProjectName());
sonarProjectRepository.save(project);
count++;
}
}
log("New projects", start, count);
}
private boolean isNewProject(SonarCollector collector, SonarProject application) {
return sonarProjectRepository.findSonarProject(
collector.getId(), application.getInstanceUrl(), application.getProjectId()) == null;
}
private boolean isNewQualityData(SonarProject project, CodeQuality codeQuality) {
return codeQualityRepository.findByCollectorItemIdAndTimestamp(
project.getId(), codeQuality.getTimestamp()) == null;
}
private void log(String marker, long start) {
log(marker, start, null);
}
private void log(String text, long start, Integer count) {
long end = System.currentTimeMillis();
String elapsed = ((end - start) / 1000) + "s";
String token2 = "";
String token3;
if (count == null) {
token3 = StringUtils.leftPad(elapsed, 30 - text.length());
} else {
String countStr = count.toString();
token2 = StringUtils.leftPad(countStr, 20 - text.length() );
token3 = StringUtils.leftPad(elapsed, 10 );
}
LOG.info(text + token2 + token3);
}
private void logInstanceBanner(String instanceUrl) {
LOG.info("------------------------------");
LOG.info(instanceUrl);
LOG.info("------------------------------");
}
}