]> source.dussan.org Git - sonarqube.git/commitdiff
Replace table ANALYSIS_REPORTS by CE_QUEUE and CE_ACTIVITY
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 9 Sep 2015 16:14:31 +0000 (18:14 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 18 Sep 2015 21:48:48 +0000 (23:48 +0200)
137 files changed:
server/sonar-server/src/main/java/org/sonar/server/batch/BatchWsModule.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java
server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java
server/sonar-server/src/main/java/org/sonar/server/computation/CeQueue.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueInitializer.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueListener.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeTask.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeTaskSubmit.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeWorker.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CeWorkerImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/CleanReportQueueListener.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ComputationStepExecutor.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineProcessingExecutorService.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineProcessingModule.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineProcessingQueue.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineProcessingQueueImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineTask.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportFiles.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessingScheduler.java
server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessingSchedulerExecutorService.java
server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessingTask.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessor.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueueCleaner.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportSubmitter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ReportTaskProcessor.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/activity/package-info.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainer.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactory.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ContainerFactoryImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitor.java
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/MutableQualityGateHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/qualitygate/QualityGateHolder.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportExtractionStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeSubmitWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeTaskWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsTaskFormatter.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWs.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWsAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/IsQueueEmptyWs.java
server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java
server/sonar-server/src/main/resources/org/sonar/server/computation/ws/CeSubmitWsAction/example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/batch/BatchWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueInitializerTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/CeWorkerImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/CleanReportQueueListenerTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineProcessingQueueImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessingSchedulerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessingTaskTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessorTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueCleanerTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ReportSubmitterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulatorTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ComputationStepsTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportExtractionStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeSubmitWsActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeTaskWsActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComputationWsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryActionMediumTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/ws/TestRequest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/ws/HistoryActionMediumTest/list_history_reports.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/computation/ws/QueueActionTest/list_queue_reports.json [deleted file]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/414_add_scan_and_dry_run_permissions.rb
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_create_ce_activity.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/932_create_ce_queue.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/933_drop_table_analysis_reports.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/934_remove_analysis_reports_from_activities.rb [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
sonar-core/src/main/java/org/sonar/core/platform/PluginRepository.java
sonar-core/src/main/java/org/sonar/core/util/Protobuf.java
sonar-db/src/main/java/org/sonar/db/Dao.java
sonar-db/src/main/java/org/sonar/db/DaoModule.java
sonar-db/src/main/java/org/sonar/db/DbClient.java
sonar-db/src/main/java/org/sonar/db/MyBatis.java
sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeActivityQuery.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/CeTaskTypes.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/ce/package-info.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDao.java [deleted file]
sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDto.java [deleted file]
sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportMapper.java [deleted file]
sonar-db/src/main/java/org/sonar/db/compute/package-info.java [deleted file]
sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
sonar-db/src/main/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivities.java [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/compute/AnalysisReportMapper.xml [deleted file]
sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java
sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/compute/AnalysisReportDaoTest.java [deleted file]
sonar-db/src/test/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivitiesTest.java [new file with mode: 0644]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/any-analysis-reports.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/empty.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/insert-result.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/one_analysis_report.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_oldest_pending.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/select.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/three_analysis_reports.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/truncate-result.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending-result.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending.xml [deleted file]
sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/zip.zip [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/TestSystem2.java [new file with mode: 0644]
sonar-ws/src/main/gen-java/org/sonarqube/ws/WsCe.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-ce.proto [new file with mode: 0644]

index 8357272f31864bc4b3b79dbad908103650deab5b..2d0f594eefe0c6d05627829f1ad9d11185ec7852 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.server.batch;
 
 import org.sonar.core.platform.Module;
-import org.sonar.server.computation.ws.SubmitReportAction;
 
 public class BatchWsModule extends Module {
   @Override
@@ -30,7 +29,6 @@ public class BatchWsModule extends Module {
       GlobalAction.class,
       ProjectAction.class,
       ProjectRepositoryLoader.class,
-      SubmitReportAction.class,
       IssuesAction.class,
       UsersAction.class,
       BatchWs.class);
index 1530536274ab8926ac4696f518812cb9c5403fba..8c9b2c7c109f1f1ccedb64052415fcf9868df025 100644 (file)
@@ -144,7 +144,7 @@ public class ComponentService {
     }
   }
 
-  public String create(NewComponent newComponent) {
+  public ComponentDto create(NewComponent newComponent) {
     userSession.checkGlobalPermission(GlobalPermissions.PROVISIONING);
 
     DbSession session = dbClient.openSession(false);
@@ -175,9 +175,9 @@ public class ComponentService {
       dbClient.componentIndexDao().indexResource(session, component.getId());
       session.commit();
 
-      return component.key();
+      return component;
     } finally {
-      session.close();
+      dbClient.closeSession(session);
     }
   }
 
index b83a3f73819a058287015321701174c34a58d818..2fa6e0cfe6f73820d0a18cc7fa9914815804cfd6 100644 (file)
@@ -73,12 +73,15 @@ public class DefaultRubyComponentService implements RubyComponentService {
   public Long createComponent(String key, @Nullable String branch, String name, @Nullable String qualifier) {
     // Sub view should not be created with provisioning. Will be fixed by http://jira.sonarsource.com/browse/VIEWS-296
     if (!Qualifiers.SUBVIEW.equals(qualifier)) {
-      String createdKey = componentService.create(NewComponent.create(key, name).setQualifier(qualifier).setBranch(branch));
-      ComponentDto component = (ComponentDto) resourceDao.selectByKey(createdKey);
+      ComponentDto componentDto = componentService.create(NewComponent.create(key, name).setQualifier(qualifier).setBranch(branch));
+      if (componentDto == null) {
+        throw new BadRequestException(String.format("Component not created: %s", key));
+      }
+      ComponentDto component = (ComponentDto) resourceDao.selectByKey(componentDto.getKey());
       if (component == null) {
-        throw new BadRequestException(String.format("Component not created: %s", createdKey));
+        throw new BadRequestException(String.format("Component not created: %s", key));
       }
-      permissionService.applyDefaultPermissionTemplate(createdKey);
+      permissionService.applyDefaultPermissionTemplate(component.getKey());
       return component.getId();
     }
     return null;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueue.java
new file mode 100644 (file)
index 0000000..4dfab3e
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * 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.computation;
+
+import com.google.common.base.Optional;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.server.computation.monitoring.CEQueueStatus;
+
+import static java.lang.String.format;
+
+/**
+ * Queue of pending Compute Engine tasks. Both producer and consumer actions
+ * are implemented.
+ * <p>
+ *   This class is decoupled from the regular task type {@link org.sonar.db.ce.CeTaskTypes#REPORT}.
+ * </p>
+ */
+@ServerSide
+public class CeQueue {
+
+  private final System2 system2;
+  private final DbClient dbClient;
+  private final UuidFactory uuidFactory;
+  private final CEQueueStatus queueStatus;
+  private final CeQueueListener[] listeners;
+
+  // state
+  private boolean submitPaused = false;
+  private boolean peekPaused = false;
+
+  public CeQueue(System2 system2, DbClient dbClient, UuidFactory uuidFactory,
+    CEQueueStatus queueStatus, CeQueueListener[] listeners) {
+    this.system2 = system2;
+    this.dbClient = dbClient;
+    this.uuidFactory = uuidFactory;
+    this.queueStatus = queueStatus;
+    this.listeners = listeners;
+  }
+
+  public CeTaskSubmit prepareSubmit() {
+    return new CeTaskSubmit(uuidFactory.create());
+  }
+
+  public CeTask submit(CeTaskSubmit submit) {
+    if (submitPaused) {
+      throw new IllegalStateException("Compute Engine does not currently accept new tasks");
+    }
+    CeTask task = new CeTask(submit);
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      CeQueueDto dto = new CeQueueDto();
+      dto.setUuid(task.getUuid());
+      dto.setTaskType(task.getType());
+      dto.setComponentUuid(task.getComponentUuid());
+      dto.setStatus(CeQueueDto.Status.PENDING);
+      dto.setSubmitterLogin(task.getSubmitterLogin());
+      dto.setStartedAt(null);
+      dbClient.ceQueueDao().insert(dbSession, dto);
+      dbSession.commit();
+      queueStatus.addReceived();
+      return task;
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  public Optional<CeTask> peek() {
+    if (peekPaused) {
+      return Optional.absent();
+    }
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> dto = dbClient.ceQueueDao().peek(dbSession);
+      if (!dto.isPresent()) {
+        return Optional.absent();
+      }
+      queueStatus.addInProgress();
+      return Optional.of(new CeTask(dto.get()));
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  public boolean cancel(String taskUuid) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid);
+      if (queueDto.isPresent()) {
+        if (!queueDto.get().getStatus().equals(CeQueueDto.Status.PENDING)) {
+          throw new IllegalStateException(String.format("Task is in progress and can't be cancelled [uuid=%s]", taskUuid));
+        }
+        cancel(dbSession, queueDto.get());
+        return true;
+      }
+      return false;
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  void cancel(DbSession dbSession, CeQueueDto q) {
+    CeActivityDto activityDto = new CeActivityDto(q);
+    activityDto.setStatus(CeActivityDto.Status.CANCELED);
+    remove(dbSession, new CeTask(q), q, activityDto);
+  }
+
+
+  /**
+   * Removes all the tasks from the queue, whatever their status. They are marked
+   * as {@link org.sonar.db.ce.CeActivityDto.Status#CANCELED} in past activity.
+   * This method can NOT be called when  workers are being executed, as in progress
+   * tasks can't be killed.
+   *
+   * @return the number of canceled tasks
+   */
+  public int clear() {
+    return cancelAll(true);
+  }
+
+  /**
+   * Similar as {@link #clear()}, except that the tasks with status
+   * {@link org.sonar.db.ce.CeQueueDto.Status#IN_PROGRESS} are ignored. This method
+   * can be called at runtime, even if workers are being executed.
+   *
+   * @return the number of canceled tasks
+   */
+  public int cancelAll() {
+    return cancelAll(false);
+  }
+
+  private int cancelAll(boolean includeInProgress) {
+    int count = 0;
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      for (CeQueueDto queueDto : dbClient.ceQueueDao().selectAllInAscOrder(dbSession)) {
+        if (includeInProgress || !queueDto.getStatus().equals(CeQueueDto.Status.IN_PROGRESS)) {
+          cancel(dbSession, queueDto);
+          count++;
+        }
+      }
+      return count;
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  public void remove(CeTask task, CeActivityDto.Status status) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, task.getUuid());
+      if (!queueDto.isPresent()) {
+        throw new IllegalStateException(format("Task does not exist anymore: %s", task));
+      }
+      CeActivityDto activityDto = new CeActivityDto(queueDto.get());
+      activityDto.setStatus(status);
+      Long startedAt = activityDto.getStartedAt();
+      if (startedAt != null) {
+        activityDto.setFinishedAt(system2.now());
+        long executionTime = activityDto.getFinishedAt() - startedAt;
+        activityDto.setExecutionTimeMs(executionTime);
+        if (status == CeActivityDto.Status.SUCCESS) {
+          queueStatus.addSuccess(executionTime);
+        } else {
+          queueStatus.addError(executionTime);
+        }
+      }
+      remove(dbSession, task, queueDto.get(), activityDto);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private void remove(DbSession dbSession, CeTask task, CeQueueDto queueDto, CeActivityDto activityDto) {
+    dbClient.ceActivityDao().insert(dbSession, activityDto);
+    dbClient.ceQueueDao().deleteByUuid(dbSession, queueDto.getUuid());
+    dbSession.commit();
+    for (CeQueueListener listener : listeners) {
+      listener.onRemoved(task, activityDto.getStatus());
+    }
+  }
+
+  public void pauseSubmit() {
+    this.submitPaused = true;
+  }
+
+  public void resumeSubmit() {
+    this.submitPaused = false;
+  }
+
+  public boolean isSubmitPaused() {
+    return submitPaused;
+  }
+
+  public void pausePeek() {
+    this.peekPaused = true;
+  }
+
+  public void resumePeek() {
+    this.peekPaused = false;
+  }
+
+  public boolean isPeekPaused() {
+    return peekPaused;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueInitializer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueInitializer.java
new file mode 100644 (file)
index 0000000..661e9ba
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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.computation;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.sonar.api.platform.ServerUpgradeStatus;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.server.computation.monitoring.CEQueueStatus;
+
+/**
+ * Cleans-up the Compute Engine queue and resets the JMX counters.
+ * CE workers must not be started before execution of this class.
+ */
+@ServerSide
+public class CeQueueInitializer {
+
+  private static final Logger LOGGER = Loggers.get(CeQueueInitializer.class);
+
+  private final DbClient dbClient;
+  private final ServerUpgradeStatus serverUpgradeStatus;
+  private final ReportFiles reportFiles;
+  private final CeQueue queue;
+  private final CEQueueStatus queueStatus;
+
+  public CeQueueInitializer(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, ReportFiles reportFiles,
+    CeQueue queue, CEQueueStatus queueStatus) {
+    this.dbClient = dbClient;
+    this.serverUpgradeStatus = serverUpgradeStatus;
+    this.reportFiles = reportFiles;
+    this.queue = queue;
+    this.queueStatus = queueStatus;
+  }
+
+  /**
+   * Do not rename. Used at server startup.
+   */
+  public void start() {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      initJmxCounters(dbSession);
+
+      if (serverUpgradeStatus.isUpgraded()) {
+        cleanOnUpgrade();
+      } else {
+        verifyConsistency(dbSession);
+      }
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private void cleanOnUpgrade() {
+    // we assume that pending tasks are not compatible with the new version
+    // and can't be processed
+    LOGGER.info("Cancel all pending tasks (due to upgrade)");
+    queue.clear();
+  }
+
+  private void verifyConsistency(DbSession dbSession) {
+    // server is not being upgraded
+    dbClient.ceQueueDao().resetAllToPendingStatus(dbSession);
+    dbSession.commit();
+
+    // verify that the report files are available for the tasks in queue
+    Set<String> uuidsInQueue = new HashSet<>();
+    for (CeQueueDto queueDto : dbClient.ceQueueDao().selectAllInAscOrder(dbSession)) {
+      uuidsInQueue.add(queueDto.getUuid());
+      if (CeTaskTypes.REPORT.equals(queueDto.getTaskType()) && !reportFiles.fileForUuid(queueDto.getUuid()).exists()) {
+        // the report is not available on file system
+        queue.cancel(dbSession, queueDto);
+      }
+    }
+
+    // clean-up filesystem
+    for (String uuid : reportFiles.listUuids()) {
+      if (!uuidsInQueue.contains(uuid)) {
+        reportFiles.deleteIfExists(uuid);
+      }
+    }
+  }
+
+  private void initJmxCounters(DbSession dbSession) {
+    queueStatus.initPendingCount(dbClient.ceQueueDao().countAll(dbSession));
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueListener.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeQueueListener.java
new file mode 100644 (file)
index 0000000..420c660
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.computation;
+
+import org.sonar.db.ce.CeActivityDto;
+
+public interface CeQueueListener {
+
+  void onRemoved(CeTask task, CeActivityDto.Status status);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeTask.java
new file mode 100644 (file)
index 0000000..3828402
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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.computation;
+
+import com.google.common.base.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.db.ce.CeQueueDto;
+
+@Immutable
+public class CeTask {
+
+  private final String type;
+  private final String uuid;
+  private final String componentUuid;
+  private final String submitterLogin;
+
+  public CeTask(String uuid, String type, @Nullable String componentUuid, @Nullable String submitterLogin) {
+    this.uuid = uuid;
+    this.type = type;
+    this.componentUuid = componentUuid;
+    this.submitterLogin = submitterLogin;
+  }
+
+  CeTask(CeTaskSubmit submit) {
+    this.uuid = submit.getUuid();
+    this.type = submit.getType();
+    this.componentUuid = submit.getComponentUuid();
+    this.submitterLogin = submit.getSubmitterLogin();
+  }
+
+  CeTask(CeQueueDto dto) {
+    this.uuid = dto.getUuid();
+    this.type = dto.getTaskType();
+    this.componentUuid = dto.getComponentUuid();
+    this.submitterLogin = dto.getSubmitterLogin();
+  }
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  @CheckForNull
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  @CheckForNull
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("componentUuid", componentUuid)
+      .add("uuid", uuid)
+      .add("type", type)
+      .add("submitterLogin", submitterLogin)
+      .toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CeTask ceTask = (CeTask) o;
+    return uuid.equals(ceTask.uuid);
+  }
+
+  @Override
+  public int hashCode() {
+    return uuid.hashCode();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeTaskSubmit.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeTaskSubmit.java
new file mode 100644 (file)
index 0000000..ab2c251
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.computation;
+
+public class CeTaskSubmit {
+
+  private final String uuid;
+  private String type;
+  private String componentUuid;
+  private String submitterLogin;
+
+  CeTaskSubmit(String uuid) {
+    this.uuid = uuid;
+  }
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  public void setComponentUuid(String s) {
+    this.componentUuid = s;
+  }
+
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  public void setSubmitterLogin(String s) {
+    this.submitterLogin = s;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeWorker.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeWorker.java
new file mode 100644 (file)
index 0000000..f3cf7df
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.computation;
+
+/**
+ * Worker that executes the tasks got from the queue
+ */
+public interface CeWorker extends Runnable {
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeWorkerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeWorkerImpl.java
new file mode 100644 (file)
index 0000000..3e2f8d2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.computation;
+
+import com.google.common.base.Optional;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.logs.Profiler;
+import org.sonar.db.ce.CeActivityDto;
+
+public class CeWorkerImpl implements CeWorker {
+
+  private static final Logger LOG = Loggers.get(CeWorkerImpl.class);
+
+  private final CeQueue queue;
+  private final ReportTaskProcessor reportTaskProcessor;
+
+  public CeWorkerImpl(CeQueue queue, ReportTaskProcessor reportTaskProcessor) {
+    this.queue = queue;
+    this.reportTaskProcessor = reportTaskProcessor;
+  }
+
+  @Override
+  public void run() {
+    Profiler profiler = Profiler.create(LOG).start();
+    CeTask task;
+    try {
+      Optional<CeTask> taskOpt = queue.peek();
+      if (!taskOpt.isPresent()) {
+        return;
+      }
+      task = taskOpt.get();
+    } catch (Exception e) {
+      LOG.error("Failed to pop the queue of analysis reports", e);
+      return;
+    }
+
+    try {
+      reportTaskProcessor.process(task);
+      queue.remove(task, CeActivityDto.Status.SUCCESS);
+    } catch (Throwable e) {
+      LOG.error(String.format("Failed to process task %s", task.getUuid()), e);
+      queue.remove(task, CeActivityDto.Status.FAILED);
+    } finally {
+      profiler.stopInfo(String.format("Total thread execution of project %s (report %s)", task.getComponentUuid(), task.getUuid()));
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CleanReportQueueListener.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CleanReportQueueListener.java
new file mode 100644 (file)
index 0000000..16a793e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.computation;
+
+import org.sonar.db.ce.CeActivityDto;
+
+public class CleanReportQueueListener implements CeQueueListener {
+
+  private final ReportFiles reportFiles;
+
+  public CleanReportQueueListener(ReportFiles reportFiles) {
+    this.reportFiles = reportFiles;
+  }
+
+  @Override
+  public void onRemoved(CeTask task, CeActivityDto.Status status) {
+    reportFiles.deleteIfExists(task.getUuid());
+  }
+}
index c90f2a75f7fb4054d59d2644f5626b792a5f7e0e..8fb79cce6e4a020abc139eadfeb19f355bc720f9 100644 (file)
 package org.sonar.server.computation;
 
 import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.util.logs.Profiler;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
 import org.sonar.server.computation.step.ComputationStep;
-
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
+import org.sonar.server.computation.step.ComputationSteps;
 
 public final class ComputationStepExecutor {
-  private final Logger logger;
-  private final Listener listener;
-  private final String description;
-  private final CEQueueStatus queueStatus;
-
-  public ComputationStepExecutor(Logger logger, Listener listener, String description, CEQueueStatus queueStatus) {
-    this.logger = requireNonNull(logger);
-    this.listener = requireNonNull(listener);
-    this.description = requireNonNull(description);
-    this.queueStatus = queueStatus;
-  }
+  private static final Logger LOGGER = Loggers.get(ComputationStepExecutor.class);
 
-  public void execute(Iterable<ComputationStep> steps) {
-    queueStatus.addInProgress();
-    listener.onStart();
-    Profiler profiler = Profiler.create(logger).startDebug(description);
-    long timingSum = 0L;
-    Profiler stepProfiler = Profiler.create(logger);
-    try {
-      for (ComputationStep step : steps) {
-        stepProfiler.start();
-        step.execute();
-        timingSum += stepProfiler.stopInfo(step.getDescription());
-      }
-      long timing = logProcessingEnd(description, profiler, timingSum);
-      queueStatus.addSuccess(timing);
-      listener.onSuccess(timing);
-    } catch (Throwable e) {
-      long timing = logProcessingEnd(description, profiler, timingSum);
-      queueStatus.addError(timing);
-      listener.onError(e, timing);
-    } finally {
-      listener.onEnd();
-    }
-  }
+  private final ComputationSteps steps;
 
-  private static long logProcessingEnd(String message, Profiler profiler, long timingSum) {
-    return profiler.stopInfo(format("%s total time spent in steps=%sms", message, timingSum));
+  public ComputationStepExecutor(ComputationSteps steps) {
+    this.steps = steps;
   }
 
-  public interface Listener {
-
-    /**
-     * Called before the first ComputationStep is executed.
-     */
-    void onStart();
-
-    /**
-     * Called when on ComputationSteps have been executed and no error occurred.
-     *
-     * @param timing the duration of the execution
-     */
-    void onSuccess(long timing);
-
-    /**
-     * Called when on ComputationSteps have been executed and no error occurred.
-     *
-     * @param e the error
-     * @param timing the duration of the execution
-     */
-    void onError(Throwable e, long timing);
-
-    /**
-     * Called when all ComputationSteps have been executed, after either {@link #onSuccess(long)} or {@link #onError(Throwable, long)}
-     */
-    void onEnd();
+  public void execute() {
+    Profiler stepProfiler = Profiler.create(LOGGER);
+    for (ComputationStep step : steps.instances()) {
+      stepProfiler.start();
+      step.execute();
+      stepProfiler.stopInfo(step.getDescription());
+    }
   }
 }
index 1c3fea8fd8d837749c81983a1db43052e259fcb9..f6075d569f872137414dc4ce66eeade9e18116f2 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.computation;
 import org.sonar.server.util.StoppableScheduledExecutorService;
 
 /**
- * The {@link java.util.concurrent.ExecutorService} responsible for running {@link ComputeEngineTask}.
+ * The {@link java.util.concurrent.ExecutorService} responsible for running {@link CeWorker}.
  */
 public interface ComputeEngineProcessingExecutorService extends StoppableScheduledExecutorService {
 }
index c48cb432f7d46abb77294e0759f3de67d642c3b3..ea1d40a72a09ace8ec405eefac2aa4b6c4c54adb 100644 (file)
 package org.sonar.server.computation;
 
 import org.sonar.core.platform.Module;
+import org.sonar.server.computation.container.ContainerFactoryImpl;
 
 public class ComputeEngineProcessingModule extends Module {
   @Override
   protected void configureModule() {
     add(
+      CeWorkerImpl.class,
+      ContainerFactoryImpl.class,
+      ComputationStepExecutor.class,
+      ReportTaskProcessor.class,
       ReportProcessingScheduler.class,
       ReportProcessingSchedulerExecutorServiceImpl.class,
       ComputeEngineProcessingExecutorServiceImpl.class,
index 687aca20c590c9df9d2adc6f64391a80a4ffee59..5bef453b115f4f179be3eb2528dc7f3c7c60d143 100644 (file)
@@ -23,5 +23,5 @@ public interface ComputeEngineProcessingQueue {
   /**
    * Adds a task to the Compute Engine processing queue.
    */
-  void addTask(ComputeEngineTask task);
+  void addTask(CeWorker task);
 }
index b981002ca3099dad35b94169465718c04d7f80dc..69805c00c4fe7314eb7e53955aae7acb44016542 100644 (file)
@@ -33,7 +33,7 @@ public class ComputeEngineProcessingQueueImpl implements ComputeEngineProcessing
   private static final Logger LOG = Loggers.get(ComputeEngineProcessingQueueImpl.class);
 
   private final ComputeEngineProcessingExecutorService processingService;
-  private final ConcurrentLinkedQueue<ComputeEngineTask> queue = Queues.newConcurrentLinkedQueue();
+  private final ConcurrentLinkedQueue<CeWorker> queue = Queues.newConcurrentLinkedQueue();
 
   private final long delayBetweenTasks;
   private final long delayForFirstStart;
@@ -48,7 +48,7 @@ public class ComputeEngineProcessingQueueImpl implements ComputeEngineProcessing
   }
 
   @Override
-  public void addTask(ComputeEngineTask task) {
+  public void addTask(CeWorker task) {
     requireNonNull(task, "a ComputeEngineTask can not be null");
 
     queue.add(task);
@@ -62,7 +62,7 @@ public class ComputeEngineProcessingQueueImpl implements ComputeEngineProcessing
   private class ProcessHeadOfQueueRunnable implements Runnable {
     @Override
     public void run() {
-      ComputeEngineTask task = queue.poll();
+      CeWorker task = queue.poll();
       if (task != null) {
         try {
           task.run();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineTask.java
deleted file mode 100644 (file)
index 626c11b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.computation;
-
-/**
- * A task to be executed by the Compute Engine.
- */
-public interface ComputeEngineTask extends Runnable {
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportFiles.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportFiles.java
new file mode 100644 (file)
index 0000000..6b24daf
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.computation;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.config.Settings;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.ProcessProperties;
+
+import static java.lang.String.format;
+
+// TODO deal with temporary unzipped files
+@ServerSide
+public class ReportFiles {
+
+  private static final String ZIP_EXTENSION = "zip";
+
+  private final Settings settings;
+
+  public ReportFiles(Settings settings) {
+    this.settings = settings;
+  }
+
+  public void save(CeTaskSubmit taskSubmit, InputStream reportInput) {
+    File file = fileForUuid(taskSubmit.getUuid());
+    try {
+      FileUtils.copyInputStreamToFile(reportInput, file);
+    } catch (Exception e) {
+      FileUtils.deleteQuietly(file);
+      IOUtils.closeQuietly(reportInput);
+      throw new IllegalStateException(format("Fail to copy report to file: %s", file.getAbsolutePath()), e);
+    }
+  }
+
+  public void deleteIfExists(String taskUuid) {
+    FileUtils.deleteQuietly(fileForUuid(taskUuid));
+  }
+
+  public void deleteAll() {
+    File dir = reportDir();
+    try {
+      FileUtils.deleteDirectory(dir);
+    } catch (Exception e) {
+      throw new IllegalStateException(format("Fail to delete directory: %s", dir.getAbsolutePath()), e);
+    }
+  }
+
+  private File reportDir() {
+    return new File(settings.getString(ProcessProperties.PATH_DATA), "ce/reports");
+  }
+
+  /**
+   * The analysis report to be processed. Can't be null
+   * but may no exist on file system.
+   */
+  public File fileForUuid(String taskUuid) {
+    return new File(reportDir(), format("%s.%s", taskUuid, ZIP_EXTENSION));
+  }
+
+  public List<String> listUuids() {
+    List<String> uuids = new ArrayList<>();
+    File dir = reportDir();
+    if (dir.exists()) {
+      Collection<File> files = FileUtils.listFiles(dir, new String[]{ZIP_EXTENSION}, false);
+      for (File file : files) {
+        uuids.add(FilenameUtils.getBaseName(file.getName()));
+      }
+    }
+    return uuids;
+  }
+}
index 7bc833ff734579552d8a1443dda3ae69daac3dae..89c472b813a5ac7b91c32842b2c3e202de978535 100644 (file)
@@ -23,23 +23,14 @@ package org.sonar.server.computation;
 import java.util.concurrent.TimeUnit;
 import org.sonar.api.platform.Server;
 import org.sonar.api.platform.ServerStartHandler;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.container.ContainerFactory;
-import org.sonar.server.computation.container.ContainerFactoryImpl;
 
 /**
  * Adds tasks to the Compute Engine to process batch reports.
  */
 public class ReportProcessingScheduler implements ServerStartHandler {
-  private static final Logger LOG = Loggers.get(ReportProcessingScheduler.class);
-
   private final ReportProcessingSchedulerExecutorService reportProcessingSchedulerExecutorService;
   private final ComputeEngineProcessingQueue processingQueue;
-  private final ReportQueue queue;
-  private final ComponentContainer sqContainer;
-  private final ContainerFactory containerFactory;
+  private final CeWorker worker;
 
   private final long delayBetweenTasks;
   private final long delayForFirstStart;
@@ -47,12 +38,10 @@ public class ReportProcessingScheduler implements ServerStartHandler {
 
   public ReportProcessingScheduler(ReportProcessingSchedulerExecutorService reportProcessingSchedulerExecutorService,
     ComputeEngineProcessingQueue processingQueue,
-    ReportQueue queue, ComponentContainer sqContainer) {
+    CeWorker worker) {
     this.reportProcessingSchedulerExecutorService = reportProcessingSchedulerExecutorService;
     this.processingQueue = processingQueue;
-    this.queue = queue;
-    this.sqContainer = sqContainer;
-    this.containerFactory = new ContainerFactoryImpl();
+    this.worker = worker;
 
     this.delayBetweenTasks = 10;
     this.delayForFirstStart = 0;
@@ -71,14 +60,7 @@ public class ReportProcessingScheduler implements ServerStartHandler {
   private class AddReportProcessingToCEProcessingQueue implements Runnable {
     @Override
     public void run() {
-      try {
-        ReportQueue.Item item = queue.pop();
-        if (item != null) {
-          processingQueue.addTask(new ReportProcessingTask(queue, item, sqContainer, containerFactory));
-        }
-      } catch (Exception e) {
-        LOG.error("Failed to pop the queue of analysis reports", e);
-      }
+      processingQueue.addTask(worker);
     }
   }
 }
index 806cfd9a791cfd2aee4282507e1fc30c5b87c7c9..fb9ecd576186d1e65691977efba3ca37d47842f8 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.computation;
 import org.sonar.server.util.StoppableScheduledExecutorService;
 
 /**
- * ExecutorService responsible for adding {@link ReportProcessingTask} to {@link ReportQueue} on a regular basis.
+ * ExecutorService responsible for adding {@link CeWorkerImpl} to {@link CeQueue} on a regular basis.
  */
 public interface ReportProcessingSchedulerExecutorService extends StoppableScheduledExecutorService {
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessingTask.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessingTask.java
deleted file mode 100644 (file)
index 4b6b68b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.computation;
-
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.util.logs.Profiler;
-import org.sonar.server.computation.container.ComputeEngineContainer;
-import org.sonar.server.computation.container.ContainerFactory;
-
-/**
- * This Compute E pops a report from the queue and integrate it.
- */
-public class ReportProcessingTask implements ComputeEngineTask {
-
-  private static final Logger LOG = Loggers.get(ReportProcessingTask.class);
-
-  private final ReportQueue queue;
-  private final ReportQueue.Item item;
-  private final ComponentContainer sqContainer;
-  private final ContainerFactory containerFactory;
-
-  public ReportProcessingTask(ReportQueue queue, ReportQueue.Item item, ComponentContainer sqContainer, ContainerFactory containerFactory) {
-    this.queue = queue;
-    this.item = item;
-    this.sqContainer = sqContainer;
-    this.containerFactory = containerFactory;
-  }
-
-  @Override
-  public void run() {
-    Profiler profiler = Profiler.create(LOG).start();
-
-    ComputeEngineContainer computeEngineContainer = containerFactory.create(sqContainer, item);
-    try {
-      computeEngineContainer.getComponentByType(ReportProcessor.class).process();
-    } catch (Throwable e) {
-      LOG.error(String.format(
-        "Failed to process analysis report %d of project %s", item.dto.getId(), item.dto.getProjectKey()), e);
-    } finally {
-      computeEngineContainer.cleanup();
-
-      removeSilentlyFromQueue(item);
-    }
-    profiler.stopInfo(String.format("Total thread execution of project %s (report %d)", item.dto.getProjectKey(), item.dto.getId()));
-  }
-
-  private void removeSilentlyFromQueue(ReportQueue.Item item) {
-    try {
-      queue.remove(item);
-    } catch (Exception e) {
-      LOG.error(String.format("Failed to remove analysis report %d from queue", item.dto.getId()), e);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportProcessor.java
deleted file mode 100644 (file)
index 958cbae..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.computation;
-
-import com.google.common.base.Throwables;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.computation.activity.ActivityManager;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.computation.step.ComputationSteps;
-
-import static java.lang.String.format;
-import static org.sonar.db.compute.AnalysisReportDto.Status.FAILED;
-import static org.sonar.db.compute.AnalysisReportDto.Status.SUCCESS;
-
-public class ReportProcessor {
-
-  private final ComputationStepExecutor executor;
-  private final ComputationSteps steps;
-
-  public ReportProcessor(ComputationSteps steps,
-    ReportQueue.Item item, ActivityManager activityManager, System2 system, CEQueueStatus queueStatus) {
-    this.executor = new ComputationStepExecutor(
-      Loggers.get(ReportProcessor.class),
-      new ReportProcessingStepsExecutorListener(item, system, activityManager, queueStatus),
-        createDescription(item), queueStatus);
-    this.steps = steps;
-  }
-
-  public void process() {
-    this.executor.execute(this.steps.instances());
-  }
-
-  private static String createDescription(ReportQueue.Item item) {
-    String projectKey = item.dto.getProjectKey();
-    return format("Analysis of project %s (report %d)", projectKey, item.dto.getId());
-  }
-
-  private static class ReportProcessingStepsExecutorListener implements ComputationStepExecutor.Listener {
-    private final ReportQueue.Item item;
-    private final System2 system;
-    private final ActivityManager activityManager;
-
-    private ReportProcessingStepsExecutorListener(ReportQueue.Item item, System2 system, ActivityManager activityManager, CEQueueStatus queueStatus) {
-      this.item = item;
-      this.system = system;
-      this.activityManager = activityManager;
-    }
-
-    @Override
-    public void onStart() {
-      // nothing to do on start
-    }
-
-    @Override
-    public void onSuccess(long timing) {
-      item.dto.setStatus(SUCCESS);
-    }
-
-    @Override
-    public void onError(Throwable e, long timing) {
-      item.dto.setStatus(FAILED);
-      throw Throwables.propagate(e);
-    }
-
-    @Override
-    public void onEnd() {
-      item.dto.setFinishedAt(system.now());
-      activityManager.saveActivity(item.dto);
-    }
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueue.java
deleted file mode 100644 (file)
index 5a0607b..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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.computation;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.config.Settings;
-import org.sonar.api.server.ServerSide;
-import org.sonar.core.util.Uuids;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.MyBatis;
-import org.sonar.db.compute.AnalysisReportDao;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.process.ProcessProperties;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-
-import static org.sonar.db.compute.AnalysisReportDto.Status.PENDING;
-
-@ServerSide
-public class ReportQueue {
-  private final DbClient dbClient;
-  private final Settings settings;
-  private final CEQueueStatus queueStatus;
-
-  public ReportQueue(DbClient dbClient, Settings settings, CEQueueStatus queueStatus) {
-    this.dbClient = dbClient;
-    this.settings = settings;
-    this.queueStatus = queueStatus;
-  }
-
-  public void start() {
-    DbSession session = dbClient.openSession(false);
-    try {
-      queueStatus.initPendingCount(dao().countPending(session));
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public Item add(String projectKey, String projectName, InputStream reportData) {
-    String uuid = Uuids.create();
-    File file = reportFileForUuid(uuid);
-
-    DbSession session = dbClient.openSession(false);
-    try {
-      saveReportOnDisk(reportData, file);
-      AnalysisReportDto dto = saveReportMetadataInDatabase(projectKey, projectName, uuid, session);
-
-      return new Item(dto, file);
-    } catch (Exception e) {
-      FileUtils.deleteQuietly(file);
-      throw new IllegalStateException("Fail to store analysis report of project " + projectKey, e);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  private AnalysisReportDto saveReportMetadataInDatabase(String projectKey, String projectName, String uuid, DbSession session) {
-    AnalysisReportDto dto = new AnalysisReportDto()
-      .setProjectKey(projectKey)
-      .setProjectName(projectName)
-      .setStatus(PENDING)
-      .setUuid(uuid);
-    dao().insert(session, dto);
-    session.commit();
-    return dto;
-  }
-
-  private AnalysisReportDao dao() {
-    return dbClient.analysisReportDao();
-  }
-
-  private static void saveReportOnDisk(InputStream reportData, File file) throws IOException {
-    FileUtils.copyInputStreamToFile(reportData, file);
-  }
-
-  public void remove(Item item) {
-    DbSession session = dbClient.openSession(false);
-    try {
-      FileUtils.deleteQuietly(item.zipFile);
-      dao().delete(session, item.dto.getId());
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @CheckForNull
-  public Item pop() {
-    DbSession session = dbClient.openSession(false);
-    try {
-      AnalysisReportDto dto = dao().pop(session);
-      if (dto != null) {
-        File file = reportFileForUuid(dto.getUuid());
-        if (file.exists()) {
-          return new Item(dto, file);
-        }
-        Loggers.get(getClass()).error("Analysis report not found: " + file.getAbsolutePath());
-        dao().delete(session, dto.getId());
-        session.commit();
-      }
-      return null;
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  /**
-   * Truncates table ANALYSIS_REPORTS and delete all files from directory {data}/analysis
-   */
-  public void clear() {
-    File dir = reportsDir();
-    try {
-      FileUtils.deleteDirectory(dir);
-    } catch (IOException e) {
-      throw new IllegalStateException("Fail to delete directory: " + dir.getAbsolutePath(), e);
-    }
-
-    DbSession session = dbClient.openSession(false);
-    try {
-      dao().truncate(session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public void resetToPendingStatus() {
-    DbSession session = dbClient.openSession(false);
-    try {
-      dao().resetAllToPendingStatus(session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  /**
-   * All the reports of the queue, whatever the status
-   */
-  public List<AnalysisReportDto> all() {
-    DbSession session = dbClient.openSession(false);
-    try {
-      return dao().selectAll(session);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  /**
-   * This directory is a flat list of the reports referenced in table ANALYSIS_REPORTS.
-   * Never return null but the directory may not exist.
-   */
-  private File reportsDir() {
-    return new File(settings.getString(ProcessProperties.PATH_DATA), "analysis");
-  }
-
-  private File reportFileForUuid(String uuid) {
-    return new File(reportsDir(), String.format("%s.zip", uuid));
-  }
-
-  public static class Item {
-    public final AnalysisReportDto dto;
-    public final File zipFile;
-
-    public Item(AnalysisReportDto dto, File zipFile) {
-      this.dto = dto;
-      this.zipFile = zipFile;
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueueCleaner.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportQueueCleaner.java
deleted file mode 100644 (file)
index fb82118..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.computation;
-
-import org.picocontainer.Startable;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.platform.ServerUpgradeStatus;
-
-/**
- * Clean-up queue of reports at server startup:
- * <ul>
- *   <li>remove all reports if server being upgraded to a new version (we assume that
- *   format of reports is not forward-compatible)</li>
- *   <li>reset reports that were in status WORKING while server stopped</li>
- * </ul>
- */
-@ServerSide
-public class ReportQueueCleaner implements Startable {
-
-  private final ServerUpgradeStatus serverUpgradeStatus;
-  private final ReportQueue queue;
-
-  public ReportQueueCleaner(ServerUpgradeStatus serverUpgradeStatus, ReportQueue queue) {
-    this.serverUpgradeStatus = serverUpgradeStatus;
-    this.queue = queue;
-  }
-
-  @Override
-  public void start() {
-    if (serverUpgradeStatus.isUpgraded()) {
-      queue.clear();
-    } else {
-      queue.resetToPendingStatus();
-    }
-  }
-
-  @Override
-  public void stop() {
-    // do nothing
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportSubmitter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportSubmitter.java
new file mode 100644 (file)
index 0000000..1fe382e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.computation;
+
+import java.io.InputStream;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.server.ServerSide;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.NewComponent;
+import org.sonar.server.user.UserSession;
+
+@ServerSide
+public class ReportSubmitter {
+
+  private final CeQueue queue;
+  private final UserSession userSession;
+  private final ReportFiles reportFiles;
+  private final ComponentService componentService;
+
+  public ReportSubmitter(CeQueue queue, UserSession userSession, ReportFiles reportFiles,
+    ComponentService componentService) {
+    this.queue = queue;
+    this.userSession = userSession;
+    this.reportFiles = reportFiles;
+    this.componentService = componentService;
+  }
+
+  public CeTask submit(String projectKey, @Nullable String projectName, InputStream reportInput) {
+    userSession.checkGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
+
+    ComponentDto project = componentService.getNullableByKey(projectKey);
+    if (project == null) {
+      // the project does not exist -> requires to provision it
+      NewComponent newProject = new NewComponent(projectKey, StringUtils.defaultIfBlank(projectName, projectKey));
+      newProject.setQualifier(Qualifiers.PROJECT);
+      // no need to verify the permission "provisionning" as it's already handled by componentService
+      project = componentService.create(newProject);
+    }
+
+    // the report file must be saved before submitting the task
+    CeTaskSubmit submit = queue.prepareSubmit();
+    reportFiles.save(submit, reportInput);
+
+    submit.setType(CeTaskTypes.REPORT);
+    submit.setComponentUuid(project.uuid());
+    submit.setSubmitterLogin(userSession.getLogin());
+    return queue.submit(submit);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ReportTaskProcessor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ReportTaskProcessor.java
new file mode 100644 (file)
index 0000000..e8dc580
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.computation;
+
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.server.computation.container.ComputeEngineContainer;
+import org.sonar.server.computation.container.ContainerFactory;
+
+public class ReportTaskProcessor {
+
+  private final ContainerFactory containerFactory;
+  private final ComponentContainer serverContainer;
+
+  public ReportTaskProcessor(ContainerFactory containerFactory, ComponentContainer serverContainer) {
+    this.containerFactory = containerFactory;
+    this.serverContainer = serverContainer;
+  }
+
+  public void process(CeTask task) {
+    ComputeEngineContainer ceContainer = containerFactory.create(serverContainer, task);
+    try {
+      ceContainer.getComponentByType(ComputationStepExecutor.class).execute();
+    } finally {
+      ceContainer.cleanup();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java b/server/sonar-server/src/main/java/org/sonar/server/computation/activity/ActivityManager.java
deleted file mode 100644 (file)
index 7df6ff1..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.computation.activity;
-
-import com.google.common.base.Optional;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.MyBatis;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.ActivityService;
-
-import static org.sonar.api.utils.DateUtils.formatDateTimeNullSafe;
-import static org.sonar.api.utils.DateUtils.longToDate;
-
-public class ActivityManager {
-  private final ActivityService activityService;
-  private final DbClient dbClient;
-
-  public ActivityManager(ActivityService activityService, DbClient dbClient) {
-    this.activityService = activityService;
-    this.dbClient = dbClient;
-  }
-
-  public void saveActivity(AnalysisReportDto report) {
-    Optional<ComponentDto> projectOptional = loadProject(report.getProjectKey());
-    Activity activity = new Activity();
-    activity.setType(Activity.Type.ANALYSIS_REPORT);
-    activity.setAction("LOG_ANALYSIS_REPORT");
-    activity
-      .setData("key", String.valueOf(report.getId()))
-      .setData("projectKey", report.getProjectKey())
-      .setData("status", String.valueOf(report.getStatus()))
-      .setData("submittedAt", formatDateTimeNullSafe(longToDate(report.getCreatedAt())))
-      .setData("startedAt", formatDateTimeNullSafe(longToDate(report.getStartedAt())))
-      .setData("finishedAt", formatDateTimeNullSafe(longToDate(report.getFinishedAt())));
-    if (projectOptional.isPresent()) {
-      ComponentDto project = projectOptional.get();
-      activity
-        .setData("projectName", project.name())
-        .setData("projectUuid", project.uuid());
-    }
-    activityService.save(activity);
-  }
-
-  private Optional<ComponentDto> loadProject(String projectKey) {
-    DbSession session = dbClient.openSession(false);
-    try {
-      return dbClient.componentDao().selectByKey(session, projectKey);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/activity/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/computation/activity/package-info.java
deleted file mode 100644 (file)
index 84449c5..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.server.computation.activity;
-
-import javax.annotation.ParametersAreNonnullByDefault;
index 088dbc56e71095e73d57ab4f1d75e33f0baf2604..bb76947dbda960f588e4707da5e3948ca46a9d51 100644 (file)
 package org.sonar.server.computation.batch;
 
 import java.io.File;
-import org.sonar.server.computation.ReportQueue;
 
 public interface BatchReportDirectoryHolder {
   /**
-   * The File of the directory where the Batch report files for the current {@link ReportQueue.Item} are stored.
+   * The File of the directory where the Batch report files for the current {@link org.sonar.server.computation.CeTask} are stored.
    *
    * @throws IllegalStateException if the holder is empty (ie. there is no directory yet)
    */
index e6e3556393b731a897cf9a696736cb53ffcd64a2..f0b4bba8d1935bd3ca59ba7ccd242204016cdbb1 100644 (file)
@@ -23,6 +23,7 @@ import java.io.File;
 import java.util.Objects;
 
 public class BatchReportDirectoryHolderImpl implements MutableBatchReportDirectoryHolder {
+
   private File directory;
 
   @Override
index 4854b389fdd80296e6b615f221853732f8d2ec66..87c091348ab4c034ae26bc14cca089edb159e536 100644 (file)
@@ -21,17 +21,16 @@ package org.sonar.server.computation.container;
 
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.ContainerPopulator;
-import org.sonar.server.computation.ReportQueue.Item;
 
 /**
- * The Compute Engine container. Created for a specific parent {@link ComponentContainer} and a specific {@link Item}.
+ * The Compute Engine container. Created for a specific parent {@link ComponentContainer} and a specific {@link org.sonar.server.computation.CeTask}.
  */
 public interface ComputeEngineContainer extends ContainerPopulator.Container {
 
   ComponentContainer getParent();
 
   /**
-   * Clean's up resources after process has been called and has returned.
+   * Cleans up resources after process has been called and has returned.
    */
   void cleanup();
 
index 7787a6c69e6fd0e8bb82d0079e53b9dfc459fc64..c1011f6969f646ba684fb02133a005d97a519ad2 100644 (file)
 package org.sonar.server.computation.container;
 
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeTask;
 
 /**
  * Compute
  */
 public interface ContainerFactory {
 
-  ComputeEngineContainer create(ComponentContainer parent, ReportQueue.Item item);
+  ComputeEngineContainer create(ComponentContainer parent, CeTask task);
 }
index 90c0294b8b1bb43c8aaba22865383ae96210b49a..ed41a1c1f11d090313fce9934dbfc7d1e8cbe10e 100644 (file)
 package org.sonar.server.computation.container;
 
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeTask;
 
 public class ContainerFactoryImpl implements ContainerFactory {
   @Override
-  public ComputeEngineContainer create(ComponentContainer parent, ReportQueue.Item item) {
-    return new ComputeEngineContainerImpl(parent, new ReportComputeEngineContainerPopulator(item));
+  public ComputeEngineContainer create(ComponentContainer parent, CeTask task) {
+    return new ComputeEngineContainerImpl(parent, new ReportComputeEngineContainerPopulator(task));
   }
 }
index 0756e92821cd90c26ef11da2b722bb02acda3d23..453aef13d87a5fc34632d3a3053276ffefcdaf11 100644 (file)
@@ -23,10 +23,9 @@ import java.util.Arrays;
 import java.util.List;
 import org.sonar.core.issue.tracking.Tracker;
 import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.server.computation.CeTask;
 import org.sonar.server.computation.ComputationTempFolderProvider;
-import org.sonar.server.computation.ReportProcessor;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.computation.activity.ActivityManager;
+import org.sonar.server.computation.ComputationStepExecutor;
 import org.sonar.server.computation.analysis.ReportAnalysisMetadataHolder;
 import org.sonar.server.computation.batch.BatchReportDirectoryHolderImpl;
 import org.sonar.server.computation.batch.BatchReportReaderImpl;
@@ -85,16 +84,16 @@ import org.sonar.server.computation.step.ReportComputationSteps;
 import org.sonar.server.view.index.ViewIndex;
 
 public final class ReportComputeEngineContainerPopulator implements ContainerPopulator<ComputeEngineContainer> {
-  private final ReportQueue.Item item;
+  private final CeTask task;
 
-  public ReportComputeEngineContainerPopulator(ReportQueue.Item item) {
-    this.item = item;
+  public ReportComputeEngineContainerPopulator(CeTask task) {
+    this.task = task;
   }
 
   @Override
   public void populateContainer(ComputeEngineContainer container) {
     ComputationSteps steps = new ReportComputationSteps(container);
-    container.add(item);
+    container.add(task);
     container.add(steps);
     container.addSingletons(componentClasses());
     container.addSingletons(steps.orderedStepClasses());
@@ -106,85 +105,80 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
    */
   private static List componentClasses() {
     return Arrays.asList(
-        new ComputationTempFolderProvider(),
-
-        ActivityManager.class,
-
-        MetricModule.class,
-
-        // holders
-        ReportAnalysisMetadataHolder.class,
-        BatchReportDirectoryHolderImpl.class,
-        ReportTreeRootHolderImpl.class,
-        PeriodsHolderImpl.class,
-        QualityGateHolderImpl.class,
-        DebtModelHolderImpl.class,
-        SqaleRatingSettings.class,
-        ActiveRulesHolderImpl.class,
-        MeasureComputersHolderImpl.class,
-
-        BatchReportReaderImpl.class,
-
-        // repositories
-        LanguageRepositoryImpl.class,
-        MeasureRepositoryImpl.class,
-        EventRepositoryImpl.class,
-        SettingsRepositoryImpl.class,
-        DbIdsRepositoryImpl.class,
-        QualityGateServiceImpl.class,
-        EvaluationResultTextConverterImpl.class,
-
-        // issues
-        RuleCacheLoader.class,
-        RuleRepositoryImpl.class,
-        ScmAccountToUserLoader.class,
-        ScmAccountToUser.class,
-        IssueCache.class,
-        DefaultAssignee.class,
-        IssueVisitors.class,
-        IssueLifecycle.class,
-        ComponentsWithUnprocessedIssues.class,
-        ComponentIssuesRepositoryImpl.class,
-
-        // common rules
-        CommonRuleEngineImpl.class,
-        BranchCoverageRule.class,
-        LineCoverageRule.class,
-        CommentDensityRule.class,
-        DuplicatedBlockRule.class,
-        TestErrorRule.class,
-        SkippedTestRule.class,
-
-        // order is important: DebtAggregator then NewDebtAggregator (new debt requires debt)
-        DebtCalculator.class,
-        DebtAggregator.class,
-        NewDebtCalculator.class,
-        NewDebtAggregator.class,
-        IssueAssigner.class,
-        RuleTagsCopier.class,
-        IssueCounter.class,
-
-        // visitors : order is important, measure computers must be executed at the end in order to access to every measures / issues
-        LoadComponentUuidsHavingOpenIssuesVisitor.class,
-        IntegrateIssuesVisitor.class,
-        CloseIssuesOnRemovedComponentsVisitor.class,
-        SqaleMeasuresVisitor.class,
-        LastCommitVisitor.class,
-        MeasureComputersVisitor.class,
-
-        UpdateConflictResolver.class,
-        TrackerBaseInputFactory.class,
-        TrackerRawInputFactory.class,
-        Tracker.class,
-        TrackerExecution.class,
-        BaseIssuesLoader.class,
-
-        // views
-        ViewIndex.class,
-
-        // ReportProcessor
-        ReportProcessor.class);
+      ComputationStepExecutor.class,
+      new ComputationTempFolderProvider(),
+
+    MetricModule.class,
+
+    // holders
+      ReportAnalysisMetadataHolder.class,
+      BatchReportDirectoryHolderImpl.class,
+      ReportTreeRootHolderImpl.class,
+      PeriodsHolderImpl.class,
+      QualityGateHolderImpl.class,
+      DebtModelHolderImpl.class,
+      SqaleRatingSettings.class,
+      ActiveRulesHolderImpl.class,
+      MeasureComputersHolderImpl.class,
+
+    BatchReportReaderImpl.class,
+
+    // repositories
+      LanguageRepositoryImpl.class,
+      MeasureRepositoryImpl.class,
+      EventRepositoryImpl.class,
+      SettingsRepositoryImpl.class,
+      DbIdsRepositoryImpl.class,
+      QualityGateServiceImpl.class,
+      EvaluationResultTextConverterImpl.class,
+
+    // issues
+      RuleCacheLoader.class,
+      RuleRepositoryImpl.class,
+      ScmAccountToUserLoader.class,
+      ScmAccountToUser.class,
+      IssueCache.class,
+      DefaultAssignee.class,
+      IssueVisitors.class,
+      IssueLifecycle.class,
+      ComponentsWithUnprocessedIssues.class,
+      ComponentIssuesRepositoryImpl.class,
+
+    // common rules
+      CommonRuleEngineImpl.class,
+      BranchCoverageRule.class,
+      LineCoverageRule.class,
+      CommentDensityRule.class,
+      DuplicatedBlockRule.class,
+      TestErrorRule.class,
+      SkippedTestRule.class,
+
+    // order is important: DebtAggregator then NewDebtAggregator (new debt requires debt)
+      DebtCalculator.class,
+      DebtAggregator.class,
+      NewDebtCalculator.class,
+      NewDebtAggregator.class,
+      IssueAssigner.class,
+      RuleTagsCopier.class,
+      IssueCounter.class,
+
+    // visitors : order is important, measure computers must be executed at the end in order to access to every measures / issues
+      LoadComponentUuidsHavingOpenIssuesVisitor.class,
+      IntegrateIssuesVisitor.class,
+      CloseIssuesOnRemovedComponentsVisitor.class,
+      SqaleMeasuresVisitor.class,
+      LastCommitVisitor.class,
+      MeasureComputersVisitor.class,
+
+    UpdateConflictResolver.class,
+      TrackerBaseInputFactory.class,
+      TrackerRawInputFactory.class,
+      Tracker.class,
+      TrackerExecution.class,
+      BaseIssuesLoader.class,
+
+    // views
+      ViewIndex.class);
   }
 
-
 }
index 7877c677f5b9317e0e9a8a358ea0fe0f77c82dc0..a5b525d06ac62ac64a341156ef813e36f4b3fb94 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.computation.monitoring;
 
 import java.util.LinkedHashMap;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeQueue;
 import org.sonar.server.platform.monitoring.BaseMonitorMBean;
 
 public class ComputeEngineQueueMonitor extends BaseMonitorMBean implements ComputeEngineQueueMonitorMBean {
@@ -30,7 +30,7 @@ public class ComputeEngineQueueMonitor extends BaseMonitorMBean implements Compu
     // ReportQueue initializes CEQueueStatus and is therefor a dependency of
     // ComputeEngineQueueMonitor.
     // Do not remove this parameter, it ensures start order of components
-    ReportQueue reportQueue) {
+    CeQueue ceQueue) {
     this.queueStatus = queueStatus;
   }
 
index eeffd81cd7443b541a02327775b8a34a726a9a50..07ada89613cd46e840cdd539f3eb64c7ae1adf03 100644 (file)
  */
 package org.sonar.server.computation.qualitygate;
 
-import org.sonar.server.computation.ReportQueue;
 import org.sonar.server.computation.component.Component;
 
 public interface MutableQualityGateHolder extends QualityGateHolder {
   /**
-   * Sets the quality gate for the project of the currently processed {@link ReportQueue.Item}.
+   * Sets the quality gate.
    * Settings a quality gate more than once is not allowed and it can never be set to {@code null}.
    *
    * @param qualityGate a {@link Component}, can not be {@code null}
index 9c75d885d815ebb80888a811b787c34fcbc9c7b5..ac762d22beed6afb6f104afb59926e81b9fa590f 100644 (file)
 package org.sonar.server.computation.qualitygate;
 
 import com.google.common.base.Optional;
-import org.sonar.server.computation.ReportQueue;
 
 public interface QualityGateHolder {
   /**
-   * The QualityGate for the project of the current {@link ReportQueue.Item} if there is any.
+   * The QualityGate for the project if there is any.
    *
    * @throws IllegalStateException if the holder has not been initialized (ie. we don't know yet what is the QualityGate)
    */
index 232f39392e97ecfe9f4f070c1f37de7b7be14041..49a06363f6075581eb95b201991dac6534ded37a 100644 (file)
@@ -24,7 +24,6 @@ import org.apache.commons.lang.StringUtils;
 import org.sonar.api.config.Settings;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.computation.ReportQueue;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.CrawlerDepthLimit;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
@@ -38,7 +37,7 @@ import org.sonar.server.computation.qualitygate.QualityGateService;
 import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
 
 /**
- * This step retrieves the QualityGate for the current {@link ReportQueue.Item} and stores it in
+ * This step retrieves the QualityGate and stores it in
  * {@link MutableQualityGateHolder}.
  */
 public class QualityGateLoadingStep implements ComputationStep {
index f3048e9d1fdcc88ea6109208c552579c578a468f..77a597116e87a2541c0d19be037ee84ad35a461f 100644 (file)
@@ -26,23 +26,26 @@ import org.sonar.api.utils.TempFolder;
 import org.sonar.api.utils.ZipUtils;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeTask;
+import org.sonar.server.computation.ReportFiles;
 import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
 
 /**
- * Extracts the content zip file of the {@link ReportQueue.Item} to a temp directory and adds a {@link File}
+ * Extracts the content zip file of the {@link org.sonar.server.computation.CeTask} to a temp directory and adds a {@link File}
  * representing that temp directory to the {@link MutableBatchReportDirectoryHolder}.
  */
 public class ReportExtractionStep implements ComputationStep {
   private static final Logger LOG = Loggers.get(ReportExtractionStep.class);
 
-  private final ReportQueue.Item item;
+  private final ReportFiles reportFiles;
+  private final CeTask task;
   private final TempFolder tempFolder;
   private final MutableBatchReportDirectoryHolder reportDirectoryHolder;
 
-  public ReportExtractionStep(ReportQueue.Item item, TempFolder tempFolder, MutableBatchReportDirectoryHolder reportDirectoryHolder) {
-    this.item = item;
+  public ReportExtractionStep(ReportFiles reportFiles, CeTask task, TempFolder tempFolder,
+    MutableBatchReportDirectoryHolder reportDirectoryHolder) {
+    this.reportFiles = reportFiles;
+    this.task = task;
     this.tempFolder = tempFolder;
     this.reportDirectoryHolder = reportDirectoryHolder;
   }
@@ -50,23 +53,20 @@ public class ReportExtractionStep implements ComputationStep {
   @Override
   public void execute() {
     File dir = tempFolder.newDir();
+    File zip = reportFiles.fileForUuid(task.getUuid());
     try {
-      Profiler profiler = Profiler.createIfDebug(LOG).start();
-      ZipUtils.unzip(item.zipFile, dir);
-      if (profiler.isDebugEnabled()) {
-        String message = String.format("Report extracted | size=%s | project=%s",
-            FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(dir)), item.dto.getProjectKey());
-        profiler.stopDebug(message);
-      }
+      ZipUtils.unzip(zip, dir);
       reportDirectoryHolder.setDirectory(dir);
+      LOG.info("Analysis report extracted | size={} | compressed={}",
+        FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(dir)), FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(zip)));
     } catch (IOException e) {
-      throw new IllegalStateException(String.format("Fail to unzip %s into %s", item.zipFile, dir), e);
+      throw new IllegalStateException(String.format("Fail to unzip %s into %s", zip, dir), e);
     }
   }
 
   @Override
   public String getDescription() {
-    return "Extracting batch report to temp directory";
+    return "Uncompress report";
   }
 
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeSubmitWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeSubmitWsAction.java
new file mode 100644 (file)
index 0000000..86c2539
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.computation.ws;
+
+import java.io.InputStream;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.computation.CeTask;
+import org.sonar.server.computation.ReportProcessingScheduler;
+import org.sonar.server.computation.ReportSubmitter;
+import org.sonar.server.ws.WsUtils;
+import org.sonarqube.ws.WsCe;
+
+/**
+ * POST api/ce/submit
+ * <p>Submits an analysis report to the queue of Compute Engine</p>
+ */
+public class CeSubmitWsAction implements CeWsAction {
+
+  public static final String PARAM_PROJECT_KEY = "projectKey";
+  public static final String PARAM_PROJECT_NAME = "projectName";
+  public static final String PARAM_REPORT_DATA = "report";
+
+  private final ReportSubmitter reportSubmitter;
+  private final ReportProcessingScheduler reportProcessingScheduler;
+
+  public CeSubmitWsAction(ReportSubmitter reportSubmitter, ReportProcessingScheduler reportProcessingScheduler) {
+    this.reportSubmitter = reportSubmitter;
+    this.reportProcessingScheduler = reportProcessingScheduler;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("submit")
+      .setDescription("Submit an analysis report to the queue of Compute Engine. Report is processed asynchronously.")
+      .setPost(true)
+      .setInternal(true)
+      .setHandler(this)
+      .setResponseExample(getClass().getResource("CeSubmitWsAction/example.json"));
+
+    action
+      .createParam(PARAM_PROJECT_KEY)
+      .setRequired(true)
+      .setDescription("Key of project")
+      .setExampleValue("my_project");
+
+    action
+      .createParam(PARAM_PROJECT_NAME)
+      .setRequired(false)
+      .setDescription("Optional name of the project, used only if the project does not exist yet.")
+      .setExampleValue("My Project");
+
+    action
+      .createParam(PARAM_REPORT_DATA)
+      .setRequired(true)
+      .setDescription("Report file. Format is not an API, it changes among SonarQube versions.");
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    String projectKey = wsRequest.mandatoryParam(PARAM_PROJECT_KEY);
+    String projectName = StringUtils.defaultIfBlank(wsRequest.param(PARAM_PROJECT_NAME), projectKey);
+    InputStream reportInput = wsRequest.paramAsInputStream(PARAM_REPORT_DATA);
+
+    CeTask task = reportSubmitter.submit(projectKey, projectName, reportInput);
+    reportProcessingScheduler.startAnalysisTaskNow();
+
+    WsCe.SubmitResponse submitResponse = WsCe.SubmitResponse.newBuilder()
+      .setTaskId(task.getUuid())
+      .setProjectId(task.getComponentUuid())
+      .build();
+    WsUtils.writeProtobuf(submitResponse, wsRequest, wsResponse);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeTaskWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeTaskWsAction.java
new file mode 100644 (file)
index 0000000..1cd3931
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.computation.ws;
+
+import com.google.common.base.Optional;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsUtils;
+import org.sonarqube.ws.WsCe;
+
+public class CeTaskWsAction implements CeWsAction {
+
+  public static final String ACTION = "task";
+
+  public static final String PARAM_TASK_ID = "id";
+
+  private final DbClient dbClient;
+  private final CeWsTaskFormatter wsTaskFormatter;
+  private final UserSession userSession;
+
+  public CeTaskWsAction(DbClient dbClient, CeWsTaskFormatter wsTaskFormatter, UserSession userSession) {
+    this.dbClient = dbClient;
+    this.wsTaskFormatter = wsTaskFormatter;
+    this.userSession = userSession;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction(ACTION)
+      .setDescription("Task information")
+      .setInternal(true)
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_TASK_ID)
+      .setRequired(true)
+      .setDescription("Id of task")
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    userSession.checkGlobalPermission(UserRole.ADMIN);
+
+    String taskId = wsRequest.mandatoryParam(PARAM_TASK_ID);
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      WsCe.TaskResponse.Builder wsTaskResponse = WsCe.TaskResponse.newBuilder();
+      Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskId);
+      if (queueDto.isPresent()) {
+        wsTaskResponse.setTask(wsTaskFormatter.format(queueDto.get()));
+      } else {
+        Optional<CeActivityDto> activityDto = dbClient.ceActivityDao().selectByUuid(dbSession, taskId);
+        if (activityDto.isPresent()) {
+          wsTaskResponse.setTask(wsTaskFormatter.format(activityDto.get()));
+        } else {
+          throw new NotFoundException();
+        }
+      }
+      WsUtils.writeProtobuf(wsTaskResponse.build(), wsRequest, wsResponse);
+
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWs.java
new file mode 100644 (file)
index 0000000..45d79d0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.computation.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class CeWs implements WebService {
+
+  public static final String ENDPOINT = "api/ce";
+
+  private final CeWsAction[] actions;
+
+  public CeWs(CeWsAction... actions) {
+    this.actions = actions;
+  }
+
+  @Override
+  public void define(Context context) {
+    NewController controller = context
+      .createController(ENDPOINT)
+      .setDescription("Compute Engine");
+    for (CeWsAction action : actions) {
+      action.define(controller);
+    }
+    controller.done();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsAction.java
new file mode 100644 (file)
index 0000000..fb695b0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.computation.ws;
+
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.ws.WsAction;
+
+/**
+ * Used by {@link CeWs} to loop over all its actions
+ */
+interface CeWsAction extends WsAction {
+  @Override
+  void define(WebService.NewController controller);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsTaskFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsTaskFormatter.java
new file mode 100644 (file)
index 0000000..186175a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.computation.ws;
+
+import java.util.Date;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonarqube.ws.WsCe;
+
+public class CeWsTaskFormatter {
+
+  private final ComponentService componentService;
+
+  public CeWsTaskFormatter(ComponentService componentService) {
+    this.componentService = componentService;
+  }
+
+  public WsCe.Task format(CeQueueDto dto) {
+    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
+    builder.setId(dto.getUuid());
+    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
+    builder.setTaskType(dto.getTaskType());
+    if (dto.getComponentUuid() != null) {
+      builder.setComponentId(dto.getComponentUuid());
+      buildComponent(builder, dto.getComponentUuid());
+    }
+    if (dto.getSubmitterLogin() != null) {
+      builder.setSubmitterLogin(dto.getSubmitterLogin());
+    }
+    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getCreatedAt())));
+    if (dto.getStartedAt() != null) {
+      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
+    }
+    return builder.build();
+  }
+
+  public WsCe.Task format(CeActivityDto dto) {
+    WsCe.Task.Builder builder = WsCe.Task.newBuilder();
+    builder.setId(dto.getUuid());
+    builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name()));
+    builder.setTaskType(dto.getTaskType());
+    if (dto.getComponentUuid() != null) {
+      builder.setComponentId(dto.getComponentUuid());
+      buildComponent(builder, dto.getComponentUuid());
+    }
+    if (dto.getSubmitterLogin() != null) {
+      builder.setSubmitterLogin(dto.getSubmitterLogin());
+    }
+    builder.setSubmittedAt(DateUtils.formatDateTime(new Date(dto.getCreatedAt())));
+    if (dto.getStartedAt() != null) {
+      builder.setStartedAt(DateUtils.formatDateTime(new Date(dto.getStartedAt())));
+    }
+    if (dto.getFinishedAt() != null) {
+      builder.setFinishedAt(DateUtils.formatDateTime(new Date(dto.getFinishedAt())));
+    }
+    if (dto.getExecutionTimeMs() != null) {
+      builder.setExecutionTimeMs(dto.getExecutionTimeMs());
+    }
+    return builder.build();
+  }
+
+  private void buildComponent(WsCe.Task.Builder builder, String componentUuid) {
+    ComponentDto project = componentService.getNonNullByUuid(componentUuid);
+    if (project != null) {
+      builder.setComponentKey(project.getKey());
+      builder.setComponentName(project.name());
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWs.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWs.java
deleted file mode 100644 (file)
index 4150739..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.sonar.api.server.ws.WebService;
-
-/**
- * Web service to interact with the "computation" stack :
- * <ul>
- *   <li>queue of analysis reports to be integrated</li>
- *   <li>consolidation and aggregation of analysis measures</li>
- *   <li>persistence in datastores (database/elasticsearch)</li>
- * </ul>
- */
-public class ComputationWs implements WebService {
-  public static final String ENDPOINT = "api/computation";
-
-  private final ComputationWsAction[] actions;
-
-  public ComputationWs(ComputationWsAction... actions) {
-    this.actions = actions;
-  }
-
-  @Override
-  public void define(Context context) {
-    NewController controller = context
-      .createController(ENDPOINT)
-      .setDescription("Analysis reports processed");
-    for (ComputationWsAction action : actions) {
-      action.define(controller);
-    }
-    controller.done();
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComputationWsAction.java
deleted file mode 100644 (file)
index 65edafb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.ws.WsAction;
-
-/**
- * Used by {@link ComputationWs} to
- * loop over all its actions
- */
-interface ComputationWsAction extends WsAction {
-  @Override
-  void define(WebService.NewController controller);
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/HistoryAction.java
deleted file mode 100644 (file)
index 0320fcd..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.sonar.api.server.ws.Request;
-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.permission.GlobalPermissions;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.index.ActivityDoc;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.activity.index.ActivityQuery;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.es.SearchResult;
-import org.sonar.server.issue.ws.IssuesWs;
-import org.sonar.server.user.UserSession;
-
-import java.util.Arrays;
-import java.util.Map;
-
-// FIXME replace by api/activities/search
-public class HistoryAction implements ComputationWsAction {
-  private final ActivityIndex activityIndex;
-  private final UserSession userSession;
-
-  public HistoryAction(ActivityIndex activityIndex, UserSession userSession) {
-    this.activityIndex = activityIndex;
-    this.userSession = userSession;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller
-      .createAction("history")
-      .setDescription("Past integrations of analysis reports")
-      .setSince("5.0")
-      .setInternal(true)
-      .setHandler(this);
-
-    action.addPagingParams(10);
-  }
-
-  @Override
-  public void handle(Request request, Response response) {
-    userSession.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
-
-    ActivityQuery query = new ActivityQuery();
-    query.setTypes(Arrays.asList(Activity.Type.ANALYSIS_REPORT.name()));
-
-    SearchOptions options = new SearchOptions();
-    options.setPage(request.mandatoryParamAsInt(IssuesWs.Param.PAGE), request.mandatoryParamAsInt(IssuesWs.Param.PAGE_SIZE));
-    SearchResult<ActivityDoc> results = activityIndex.search(query, options);
-
-    JsonWriter json = response.newJsonWriter().beginObject();
-    options.writeJson(json, results.getTotal());
-    writeReports(results, json);
-    json.endObject().close();
-  }
-
-  private void writeReports(SearchResult<ActivityDoc> result, JsonWriter json) {
-    json.name("reports").beginArray();
-    for (ActivityDoc doc : result.getDocs()) {
-      json.beginObject();
-      for (Map.Entry<String, String> detail : doc.getDetails().entrySet()) {
-        json.prop(detail.getKey(), detail.getValue());
-      }
-      json.endObject();
-    }
-    json.endArray();
-  }
-}
index fb247eac52d2030697f4f2494c094fddc18a5887..a789d61c94a806192ccdff4b275358b206f67dc0 100644 (file)
@@ -25,10 +25,8 @@ 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.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-
-import java.util.List;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
 
 /**
  * Internal WebService with one action
@@ -38,8 +36,8 @@ public class IsQueueEmptyWs implements WebService {
 
   private final IsQueueEmptyAction action;
 
-  public IsQueueEmptyWs(ReportQueue queue) {
-    this.action = new IsQueueEmptyAction(queue);
+  public IsQueueEmptyWs(DbClient dbClient) {
+    this.action = new IsQueueEmptyAction(dbClient);
   }
 
   @Override
@@ -52,26 +50,29 @@ public class IsQueueEmptyWs implements WebService {
   }
 
   static class IsQueueEmptyAction implements RequestHandler {
-    private final ReportQueue queue;
+    private final DbClient dbClient;
 
-    public IsQueueEmptyAction(ReportQueue queue) {
-      this.queue = queue;
+    public IsQueueEmptyAction(DbClient dbClient) {
+      this.dbClient = dbClient;
     }
 
     public void define(WebService.NewController controller) {
       controller
         .createAction("is_queue_empty")
-        .setDescription("Check if the analysis report queue is empty")
+        .setDescription("Check if the queue of Compute Engine is empty")
         .setInternal(true)
         .setHandler(this);
     }
 
     @Override
     public void handle(Request request, Response response) throws Exception {
-      List<AnalysisReportDto> reports = queue.all();
-      boolean isQueueEmpty = reports.isEmpty();
-
-      IOUtils.write(String.valueOf(isQueueEmpty), response.stream().output());
+      DbSession dbSession = dbClient.openSession(false);
+      try {
+        boolean isQueueEmpty = dbClient.ceQueueDao().selectAllInAscOrder(dbSession).isEmpty();
+        IOUtils.write(String.valueOf(isQueueEmpty), response.stream().output());
+      } finally {
+        dbClient.closeSession(dbSession);
+      }
     }
   }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/QueueAction.java
deleted file mode 100644 (file)
index 1ea1a48..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-
-import java.util.List;
-
-import static org.sonar.api.utils.DateUtils.longToDate;
-
-/**
- * @since 5.0
- */
-public class QueueAction implements ComputationWsAction {
-  private final ReportQueue queue;
-
-  public QueueAction(ReportQueue queue) {
-    this.queue = queue;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    controller
-      .createAction("queue")
-      .setDescription("List all the active analysis reports")
-      .setSince("5.0")
-      .setInternal(true)
-      .setHandler(this);
-  }
-
-  @Override
-  public void handle(Request request, Response response) throws Exception {
-    List<AnalysisReportDto> reports = queue.all();
-
-    JsonWriter json = response.newJsonWriter().beginObject();
-    writeReports(reports, json);
-    json.endObject();
-    json.close();
-  }
-
-  private static void writeReports(List<AnalysisReportDto> reports, JsonWriter json) {
-    json.name("reports").beginArray();
-    for (AnalysisReportDto report : reports) {
-      json.beginObject();
-      json.prop("key", report.getId());
-      json.prop("projectKey", report.getProjectKey());
-      json.prop("projectName", report.getProjectName());
-      json.propDateTime("startedAt", longToDate(report.getStartedAt()));
-      json.propDateTime("finishedAt", longToDate(report.getFinishedAt()));
-      json.propDateTime("submittedAt", longToDate(report.getCreatedAt()));
-      json.prop("status", report.getStatus().toString());
-      json.endObject();
-    }
-    json.endArray();
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/SubmitReportAction.java
deleted file mode 100644 (file)
index a908efa..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.computation.ws;
-
-import java.io.InputStream;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.computation.ReportProcessingScheduler;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.user.UserSession;
-
-public class SubmitReportAction implements ComputationWsAction {
-
-  public static final String ACTION = "submit_report";
-  public static final String PARAM_PROJECT_KEY = "projectKey";
-  public static final String PARAM_PROJECT_NAME = "projectName";
-  public static final String PARAM_REPORT_DATA = "report";
-
-  private final ReportQueue queue;
-  private final ReportProcessingScheduler workerLauncher;
-  private final UserSession userSession;
-  private final CEQueueStatus queueStatus;
-
-  public SubmitReportAction(ReportQueue queue, ReportProcessingScheduler workerLauncher, UserSession userSession, CEQueueStatus queueStatus) {
-    this.queue = queue;
-    this.workerLauncher = workerLauncher;
-    this.userSession = userSession;
-    this.queueStatus = queueStatus;
-  }
-
-  @Override
-  public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction(ACTION)
-      .setDescription("Submit an analysis report to the queue. Report is integrated asynchronously.")
-      .setPost(true)
-      .setInternal(true)
-      .setHandler(this);
-
-    action
-      .createParam(PARAM_PROJECT_KEY)
-      .setRequired(true)
-      .setDescription("Project key")
-      .setExampleValue("org.codehaus.sonar:sonar");
-
-    action
-      .createParam(PARAM_PROJECT_NAME)
-      .setRequired(true)
-      .setDescription("Project name")
-      .setExampleValue("SonarQube");
-
-    action
-      .createParam(PARAM_REPORT_DATA)
-      .setRequired(true)
-      .setDescription("Report file. Format is not an API, it changes among SonarQube versions.");
-  }
-
-  @Override
-  public void handle(Request request, Response response) throws Exception {
-    userSession.checkGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
-    String projectKey = request.mandatoryParam(PARAM_PROJECT_KEY);
-    String projectName = request.mandatoryParam(PARAM_PROJECT_NAME);
-    InputStream reportData = request.paramAsInputStream(PARAM_REPORT_DATA);
-    try {
-      ReportQueue.Item item = queue.add(projectKey, projectName, reportData);
-      queueStatus.addReceived();
-      workerLauncher.startAnalysisTaskNow();
-      response.newJsonWriter()
-        .beginObject()
-        // do not write integer for forward-compatibility, for example
-        // if we want to write UUID later
-        .prop("key", String.valueOf(item.dto.getId()))
-        .endObject()
-        .close();
-    } finally {
-      IOUtils.closeQuietly(reportData);
-    }
-  }
-}
index 5a1c1e91476de103993446c580571c8f918fd916..9f21e781cd25651c3c99794d32c1928a4c5191dc 100644 (file)
@@ -64,14 +64,19 @@ import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.ws.ComponentsWs;
 import org.sonar.server.component.ws.EventsWs;
 import org.sonar.server.component.ws.ResourcesWs;
+import org.sonar.server.computation.CeQueue;
+import org.sonar.server.computation.CeQueueInitializer;
+import org.sonar.server.computation.CleanReportQueueListener;
 import org.sonar.server.computation.ComputeEngineProcessingModule;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.ReportFiles;
+import org.sonar.server.computation.ReportSubmitter;
 import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
 import org.sonar.server.computation.monitoring.ComputeEngineQueueMonitor;
-import org.sonar.server.computation.ws.ComputationWs;
-import org.sonar.server.computation.ws.HistoryAction;
+import org.sonar.server.computation.ws.CeSubmitWsAction;
+import org.sonar.server.computation.ws.CeTaskWsAction;
+import org.sonar.server.computation.ws.CeWs;
+import org.sonar.server.computation.ws.CeWsTaskFormatter;
 import org.sonar.server.computation.ws.IsQueueEmptyWs;
-import org.sonar.server.computation.ws.QueueAction;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.dashboard.template.GlobalDefaultDashboard;
 import org.sonar.server.dashboard.template.ProjectDefaultDashboard;
@@ -711,17 +716,21 @@ public class PlatformLevel4 extends PlatformLevel {
       // Compute engine
       CEQueueStatusImpl.class,
       ComputeEngineQueueMonitor.class,
-      ReportQueue.class,
+      CeQueue.class,
+      CleanReportQueueListener.class,
+      ReportFiles.class,
       ComputeEngineProcessingModule.class,
-      ComputationWs.class,
+      CeWs.class,
+      CeWsTaskFormatter.class,
+      CeTaskWsAction.class,
+      CeSubmitWsAction.class,
       IsQueueEmptyWs.class,
-      QueueAction.class,
-      HistoryAction.class,
       DefaultPeriodCleaner.class,
       ProjectCleaner.class,
       ProjectSettingsFactory.class,
       IndexPurgeListener.class,
-
+      ReportSubmitter.class,
+      CeQueueInitializer.class,
       // Views plugin
       ViewsBootstrap.class,
       ViewsStopper.class,
index 80141a36266ea1e41006e462c7a8add1df8c4819..f463289c4558f7a4d3a2c321dcb27ad7b683aee2 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.platform.platformlevel;
 
-import org.sonar.server.computation.ReportQueueCleaner;
+import org.sonar.server.computation.CeQueueInitializer;
 import org.sonar.server.issue.filter.RegisterIssueFilters;
 import org.sonar.server.platform.ServerLifecycleNotifier;
 import org.sonar.server.qualitygate.RegisterQualityGates;
@@ -62,7 +62,6 @@ public class PlatformLevelStartup extends PlatformLevel {
       RenameDeprecatedPropertyKeys.class,
       LogServerId.class,
       RegisterServletFilters.class,
-      ReportQueueCleaner.class,
       RegisterIssueFilters.class,
       RenameIssueWidgets.class,
       ServerLifecycleNotifier.class);
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/CeSubmitWsAction/example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/CeSubmitWsAction/example.json
new file mode 100644 (file)
index 0000000..7cee04f
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "taskId": "TASK_1",
+  "projectId": "PROJECT_1"
+}
index 009d79afd9a3f63a3a7238fce4d5525666cb8d00..997ac69ffec8dc94dbf8486d9b0435d1e31acd93 100644 (file)
@@ -29,7 +29,7 @@ public class BatchWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new BatchWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(10);
+    assertThat(container.size()).isEqualTo(9);
   }
 
 }
index f98d960959e8df1456a4d8a61fcffc60b83c9c14..437bc00738f508314f8c724809ca49b1627e8877 100644 (file)
@@ -270,7 +270,7 @@ public class ComponentServiceTest {
   public void create_project() {
     userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);
 
-    String key = service.create(NewComponent.create("struts", "Struts project"));
+    String key = service.create(NewComponent.create("struts", "Struts project")).getKey();
 
     ComponentDto project = service.getNullableByKey(key);
     assertThat(project.key()).isEqualTo("struts");
@@ -290,7 +290,7 @@ public class ComponentServiceTest {
   public void create_new_project_with_branch() {
     userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);
 
-    String key = service.create(NewComponent.create("struts", "Struts project").setBranch("origin/branch"));
+    String key = service.create(NewComponent.create("struts", "Struts project").setBranch("origin/branch")).getKey();
 
     ComponentDto project = service.getNullableByKey(key);
     assertThat(project.key()).isEqualTo("struts:origin/branch");
@@ -301,7 +301,7 @@ public class ComponentServiceTest {
   public void create_view() {
     userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.PROVISIONING);
 
-    String key = service.create(NewComponent.create("all-project", "All Projects").setQualifier(Qualifiers.VIEW));
+    String key = service.create(NewComponent.create("all-project", "All Projects").setQualifier(Qualifiers.VIEW)).getKey();
 
     ComponentDto project = service.getNullableByKey(key);
     assertThat(project.key()).isEqualTo("all-project");
index b4d15d288df9a1951811e53e95f143576acb5903..08ca3c7ecbb334a1821f08b4b6955a9f480d468c 100644 (file)
@@ -87,8 +87,9 @@ public class DefaultRubyComponentServiceTest {
     String componentKey = "new-project";
     String componentName = "New Project";
     String qualifier = Qualifiers.PROJECT;
-    when(resourceDao.selectByKey(componentKey)).thenReturn(ComponentTesting.newProjectDto());
-    when(componentService.create(any(NewComponent.class))).thenReturn(componentKey);
+    ComponentDto projectDto = ComponentTesting.newProjectDto().setKey(componentKey);
+    when(resourceDao.selectByKey(componentKey)).thenReturn(projectDto);
+    when(componentService.create(any(NewComponent.class))).thenReturn(projectDto);
 
     service.createComponent(componentKey, componentName, qualifier);
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueInitializerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueInitializerTest.java
new file mode 100644 (file)
index 0000000..11b4191
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.computation;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.sonar.api.platform.ServerUpgradeStatus;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.server.computation.monitoring.CEQueueStatus;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class CeQueueInitializerTest {
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  @Rule
+  public TemporaryFolder tempFolder = new TemporaryFolder();
+
+  ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
+  ReportFiles reportFiles = mock(ReportFiles.class, Mockito.RETURNS_DEEP_STUBS);
+  CeQueue queue = mock(CeQueue.class);
+  CEQueueStatus queueStatus = new CEQueueStatusImpl();
+  CeQueueInitializer underTest = new CeQueueInitializer(dbTester.getDbClient(), serverUpgradeStatus, reportFiles, queue, queueStatus);
+
+  @Test
+  public void init_jmx_counters() throws IOException {
+    insertInQueue("TASK_1", CeQueueDto.Status.PENDING);
+    insertInQueue("TASK_2", CeQueueDto.Status.PENDING);
+    // this in-progress task is going to be moved to PENDING
+    insertInQueue("TASK_3", CeQueueDto.Status.IN_PROGRESS);
+
+    underTest.start();
+
+    assertThat(queueStatus.getPendingCount()).isEqualTo(3);
+  }
+
+  @Test
+  public void init_jmx_counters_when_queue_is_empty() {
+    underTest.start();
+
+    assertThat(queueStatus.getPendingCount()).isEqualTo(0);
+  }
+
+  @Test
+  public void reset_in_progress_tasks_to_pending() throws IOException {
+    insertInQueue("TASK_1", CeQueueDto.Status.PENDING);
+    insertInQueue("TASK_2", CeQueueDto.Status.IN_PROGRESS);
+
+    underTest.start();
+
+    assertThat(dbTester.getDbClient().ceQueueDao().countByStatus(dbTester.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(2);
+    assertThat(dbTester.getDbClient().ceQueueDao().countByStatus(dbTester.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(0);
+  }
+
+  @Test
+  public void clear_queue_if_version_upgrade() {
+    when(serverUpgradeStatus.isUpgraded()).thenReturn(true);
+
+    underTest.start();
+
+    verify(queue).clear();
+  }
+
+  @Test
+  public void cancel_task_if_report_file_is_missing() throws IOException {
+    CeQueueDto task = insertInQueue("TASK_1", CeQueueDto.Status.PENDING, false);
+
+    underTest.start();
+
+    verify(queue).cancel(any(DbSession.class), eq(task));
+  }
+
+  @Test
+  public void delete_orphan_report_files() throws Exception {
+    // two files on disk but on task in queue
+    insertInQueue("TASK_1", CeQueueDto.Status.PENDING, true);
+    when(reportFiles.listUuids()).thenReturn(asList("TASK_1", "TASK_2"));
+
+    underTest.start();
+
+    verify(reportFiles).deleteIfExists("TASK_2");
+  }
+
+  private void insertInQueue(String taskUuid, CeQueueDto.Status status) throws IOException {
+    insertInQueue(taskUuid, status, true);
+  }
+
+  private CeQueueDto insertInQueue(String taskUuid, CeQueueDto.Status status, boolean createFile) throws IOException {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setComponentUuid("PROJECT_1");
+    queueDto.setUuid(taskUuid);
+    queueDto.setStatus(status);
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.getSession().commit();
+
+    File file = tempFolder.newFile();
+    when(reportFiles.fileForUuid(taskUuid)).thenReturn(file);
+    if (!createFile) {
+      file.delete();
+    }
+    return queueDto;
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/CeQueueTest.java
new file mode 100644 (file)
index 0000000..0f0939c
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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.computation;
+
+import com.google.common.base.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.server.computation.monitoring.CEQueueStatus;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+public class CeQueueTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
+
+  @Rule
+  public DbTester dbTester = DbTester.create(system2);
+
+  UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
+  CEQueueStatus queueStatus = new CEQueueStatusImpl();
+  CeQueueListener listener = mock(CeQueueListener.class);
+  CeQueue underTest = new CeQueue(system2, dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
+
+  @Test
+  public void test_submit() {
+    CeTaskSubmit submit = underTest.prepareSubmit();
+    submit.setComponentUuid("PROJECT_1");
+    submit.setType(CeTaskTypes.REPORT);
+    submit.setSubmitterLogin("rob");
+
+    CeTask task = underTest.submit(submit);
+    assertThat(task.getUuid()).isEqualTo(submit.getUuid());
+    assertThat(task.getComponentUuid()).isEqualTo("PROJECT_1");
+    assertThat(task.getSubmitterLogin()).isEqualTo("rob");
+
+    Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), submit.getUuid());
+    assertThat(queueDto.isPresent()).isTrue();
+    assertThat(queueDto.get().getTaskType()).isEqualTo(CeTaskTypes.REPORT);
+    assertThat(queueDto.get().getComponentUuid()).isEqualTo("PROJECT_1");
+    assertThat(queueDto.get().getSubmitterLogin()).isEqualTo("rob");
+    assertThat(queueDto.get().getCreatedAt()).isEqualTo(1_450_000_000_000L);
+    assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
+  }
+
+  @Test
+  public void fail_to_submit_if_paused() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Compute Engine does not currently accept new tasks");
+    underTest.pauseSubmit();
+
+    submit(CeTaskTypes.REPORT, "PROJECT_1");
+  }
+
+  @Test
+  public void test_remove() {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    Optional<CeTask> peek = underTest.peek();
+    underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS);
+
+    // queue is empty
+    assertThat(dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), task.getUuid()).isPresent()).isFalse();
+    assertThat(underTest.peek().isPresent()).isFalse();
+
+    // available in history
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(history.isPresent()).isTrue();
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
+    assertThat(history.get().getIsLast()).isTrue();
+
+    verify(listener).onRemoved(task, CeActivityDto.Status.SUCCESS);
+  }
+
+  @Test
+  public void fail_to_remove_if_not_in_queue() throws Exception {
+    expectedException.expect(IllegalStateException.class);
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.remove(task, CeActivityDto.Status.SUCCESS);
+
+    // fail
+    underTest.remove(task, CeActivityDto.Status.SUCCESS);
+  }
+
+  @Test
+  public void test_peek() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    Optional<CeTask> peek = underTest.peek();
+    assertThat(peek.isPresent()).isTrue();
+    assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
+    assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT);
+    assertThat(peek.get().getComponentUuid()).isEqualTo("PROJECT_1");
+
+    // no more pending tasks
+    peek = underTest.peek();
+    assertThat(peek.isPresent()).isFalse();
+
+    verify(listener, never()).onRemoved(eq(task), any(CeActivityDto.Status.class));
+  }
+
+  @Test
+  public void peek_nothing_if_paused() throws Exception {
+    submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.pausePeek();
+
+    Optional<CeTask> peek = underTest.peek();
+    assertThat(peek.isPresent()).isFalse();
+  }
+
+  @Test
+  public void cancel_pending() throws Exception {
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+
+    // ignore
+    boolean canceled = underTest.cancel("UNKNOWN");
+    assertThat(canceled).isFalse();
+    verifyZeroInteractions(listener);
+
+    canceled = underTest.cancel(task.getUuid());
+    assertThat(canceled).isTrue();
+    Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
+    assertThat(activity.isPresent()).isTrue();
+    assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(task, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void fail_to_cancel_if_in_progress() throws Exception {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(startsWith("Task is in progress and can't be cancelled"));
+
+    CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    underTest.peek();
+
+    underTest.cancel(task.getUuid());
+  }
+
+  @Test
+  public void cancelAll_pendings_but_not_in_progress() throws Exception {
+    CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1");
+    CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2");
+    CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3");
+    underTest.peek();
+
+    int canceledCount = underTest.cancelAll();
+    assertThat(canceledCount).isEqualTo(2);
+
+    Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid());
+    assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
+    history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid());
+    assertThat(history.isPresent()).isFalse();
+
+    verify(listener).onRemoved(pendingTask1, CeActivityDto.Status.CANCELED);
+    verify(listener).onRemoved(pendingTask2, CeActivityDto.Status.CANCELED);
+  }
+
+  @Test
+  public void pause_and_resume_submits() throws Exception {
+    assertThat(underTest.isSubmitPaused()).isFalse();
+    underTest.pauseSubmit();
+    assertThat(underTest.isSubmitPaused()).isTrue();
+    underTest.resumeSubmit();
+    assertThat(underTest.isSubmitPaused()).isFalse();
+  }
+
+  @Test
+  public void pause_and_resume_peeks() throws Exception {
+    assertThat(underTest.isPeekPaused()).isFalse();
+    underTest.pausePeek();
+    assertThat(underTest.isPeekPaused()).isTrue();
+    underTest.resumePeek();
+    assertThat(underTest.isPeekPaused()).isFalse();
+  }
+
+  private CeTask submit(String reportType, String componentUuid) {
+    CeTaskSubmit submit = underTest.prepareSubmit();
+    submit.setType(reportType);
+    submit.setComponentUuid(componentUuid);
+    return underTest.submit(submit);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/CeWorkerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/CeWorkerImplTest.java
new file mode 100644 (file)
index 0000000..aed8a4a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.computation;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeTaskTypes;
+
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class CeWorkerImplTest {
+
+  CeQueue queue = mock(CeQueue.class);
+  ReportTaskProcessor taskProcessor = mock(ReportTaskProcessor.class);
+  CeWorker underTest = new CeWorkerImpl(queue, taskProcessor);
+
+  @Test
+  public void no_pending_tasks_in_queue() throws Exception {
+    when(queue.peek()).thenReturn(Optional.<CeTask>absent());
+
+    underTest.run();
+
+    verifyZeroInteractions(taskProcessor);
+  }
+
+  @Test
+  public void peek_and_process_task() throws Exception {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", null);
+    when(queue.peek()).thenReturn(Optional.of(task));
+
+    underTest.run();
+
+    verify(taskProcessor).process(task);
+    verify(queue).remove(task, CeActivityDto.Status.SUCCESS);
+  }
+
+  @Test
+  public void fail_to_process_task() throws Exception {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", null);
+    when(queue.peek()).thenReturn(Optional.of(task));
+    doThrow(new IllegalStateException()).when(taskProcessor).process(task);
+
+    underTest.run();
+
+    verify(taskProcessor).process(task);
+    verify(queue).remove(task, CeActivityDto.Status.FAILED);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/CleanReportQueueListenerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/CleanReportQueueListenerTest.java
new file mode 100644 (file)
index 0000000..0d6a631
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.computation;
+
+import org.junit.Test;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeTaskTypes;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class CleanReportQueueListenerTest {
+
+  ReportFiles reportFiles = mock(ReportFiles.class);
+  CleanReportQueueListener underTest = new CleanReportQueueListener(reportFiles);
+
+  @Test
+  public void remove_report_file_if_success() {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", null);
+
+    underTest.onRemoved(task, CeActivityDto.Status.SUCCESS);
+    verify(reportFiles).deleteIfExists("TASK_1");
+  }
+
+  @Test
+  public void remove_report_file_if_failure() {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", null);
+
+    underTest.onRemoved(task, CeActivityDto.Status.FAILED);
+    verify(reportFiles).deleteIfExists("TASK_1");
+  }
+}
index a45fadec0fc337840b5313e663d7c127822a7bc3..3d29d79ac1eb0cb376e763458738b33abed90977 100644 (file)
@@ -54,7 +54,7 @@ public class ComputeEngineProcessingQueueImplTest {
   @Test
   public void task_in_queue_is_called_run_only_once() {
     ComputeEngineProcessingExecutorServiceAdapter processingExecutorService = new SimulateFixedRateCallsProcessingExecutorService(10);
-    CallCounterComputeEngineTask task = new CallCounterComputeEngineTask();
+    CallCounterCeWorker task = new CallCounterCeWorker();
 
     ComputeEngineProcessingQueueImpl underTest = new ComputeEngineProcessingQueueImpl(processingExecutorService);
     underTest.addTask(task);
@@ -70,25 +70,25 @@ public class ComputeEngineProcessingQueueImplTest {
     final List<Integer> nameList = new ArrayList<>();
 
     ComputeEngineProcessingQueueImpl underTest = new ComputeEngineProcessingQueueImpl(processingExecutorService);
-    underTest.addTask(new ComputeEngineTask() {
+    underTest.addTask(new CeWorker() {
       @Override
       public void run() {
         nameList.add(1);
       }
     });
-    underTest.addTask(new ComputeEngineTask() {
+    underTest.addTask(new CeWorker() {
       @Override
       public void run() {
         nameList.add(2);
       }
     });
-    underTest.addTask(new ComputeEngineTask() {
+    underTest.addTask(new CeWorker() {
       @Override
       public void run() {
         nameList.add(3);
       }
     });
-    underTest.addTask(new ComputeEngineTask() {
+    underTest.addTask(new CeWorker() {
       @Override
       public void run() {
         nameList.add(4);
@@ -105,7 +105,7 @@ public class ComputeEngineProcessingQueueImplTest {
     ComputeEngineProcessingExecutorServiceAdapter processingExecutorService = new SimulateFixedRateCallsProcessingExecutorService(1);
 
     ComputeEngineProcessingQueueImpl underTest = new ComputeEngineProcessingQueueImpl(processingExecutorService);
-    underTest.addTask(new ComputeEngineTask() {
+    underTest.addTask(new CeWorker() {
       @Override
       public void run() {
         throw new RuntimeException("This should be caught by the processing queue");
@@ -115,7 +115,7 @@ public class ComputeEngineProcessingQueueImplTest {
     underTest.onServerStart(mock(Server.class));
   }
 
-  private static class CallCounterComputeEngineTask implements ComputeEngineTask {
+  private static class CallCounterCeWorker implements CeWorker {
     int calls = 0;
 
     @Override
index 5a4e36e3f2db0ec176919b6cba14c77f5ad2d7a1..51cc29f5469095cc558a5d46bdcb6db3f2d387ea 100644 (file)
@@ -27,7 +27,6 @@ import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.sonar.api.platform.Server;
-import org.sonar.core.platform.ComponentContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
@@ -38,66 +37,41 @@ import static org.mockito.Mockito.when;
 
 public class ReportProcessingSchedulerTest {
 
-  private ReportProcessingSchedulerExecutorService batchExecutorService = mock(ReportProcessingSchedulerExecutorService.class);
-  private SimpleComputeEngineProcessingQueue processingQueue = new SimpleComputeEngineProcessingQueue();
-  private ReportQueue queue = mock(ReportQueue.class);
-  private ComponentContainer componentContainer = mock(ComponentContainer.class);
-
-  private ReportProcessingScheduler underTest = new ReportProcessingScheduler(batchExecutorService, processingQueue, queue, componentContainer);
+  ReportProcessingSchedulerExecutorService batchExecutorService = mock(ReportProcessingSchedulerExecutorService.class);
+  SimpleComputeEngineProcessingQueue processingQueue = new SimpleComputeEngineProcessingQueue();
+  CeWorker worker = mock(CeWorker.class);
+  ReportProcessingScheduler underTest = new ReportProcessingScheduler(batchExecutorService, processingQueue, worker);
 
   @Test
-  public void schedule_at_fixed_rate_adding_a_ReportProcessingTask_to_the_queue_if_there_is_item_in_ReportQueue() {
-    ReportQueue.Item item = mock(ReportQueue.Item.class);
+  public void schedule_at_fixed_rate_adding_a_ReportProcessingTask_to_the_queue() throws Exception {
     when(batchExecutorService.scheduleAtFixedRate(any(Runnable.class), eq(0L), eq(10L), eq(TimeUnit.SECONDS)))
       .thenAnswer(new ExecuteFirstArgAsRunnable());
-    when(queue.pop()).thenReturn(item);
 
     underTest.onServerStart(mock(Server.class));
 
     assertThat(processingQueue.getTasks()).hasSize(1);
-    assertThat(processingQueue.getTasks().iterator().next()).isInstanceOf(ReportProcessingTask.class);
-  }
-
-  @Test
-  public void schedule_at_fixed_rate_does_not_add_ReportProcessingTask_to_the_queue_if_there_is_no_item_in_ReportQueue() {
-    when(batchExecutorService.scheduleAtFixedRate(any(Runnable.class), eq(0L), eq(10L), eq(TimeUnit.SECONDS)))
-      .thenAnswer(new ExecuteFirstArgAsRunnable());
-
-    underTest.onServerStart(mock(Server.class));
-
-    assertThat(processingQueue.getTasks()).isEmpty();
+    assertThat(processingQueue.getTasks().iterator().next()).isInstanceOf(CeWorker.class);
   }
 
   @Test
-  public void adds_immediately_a_ReportProcessingTask_to_the_queue_if_there_is_item_in_ReportQueue() {
-    ReportQueue.Item item = mock(ReportQueue.Item.class);
+  public void adds_immediately_a_ReportProcessingTask_to_the_queue() throws Exception {
     doAnswer(new ExecuteFirstArgAsRunnable()).when(batchExecutorService).execute(any(Runnable.class));
-    when(queue.pop()).thenReturn(item);
 
     underTest.startAnalysisTaskNow();
 
     assertThat(processingQueue.getTasks()).hasSize(1);
-    assertThat(processingQueue.getTasks().iterator().next()).isInstanceOf(ReportProcessingTask.class);
-  }
-
-  @Test
-  public void adds_immediately_does_not_add_ReportProcessingTask_to_the_queue_if_there_is_item_in_ReportQueue() {
-    doAnswer(new ExecuteFirstArgAsRunnable()).when(batchExecutorService).execute(any(Runnable.class));
-
-    underTest.startAnalysisTaskNow();
-
-    assertThat(processingQueue.getTasks()).isEmpty();
+    assertThat(processingQueue.getTasks().iterator().next()).isInstanceOf(CeWorker.class);
   }
 
   private static class SimpleComputeEngineProcessingQueue implements ComputeEngineProcessingQueue {
-    private final List<ComputeEngineTask> tasks = new ArrayList<>();
+    private final List<CeWorker> tasks = new ArrayList<>();
 
     @Override
-    public void addTask(ComputeEngineTask task) {
+    public void addTask(CeWorker task) {
       tasks.add(task);
     }
 
-    public List<ComputeEngineTask> getTasks() {
+    public List<CeWorker> getTasks() {
       return tasks;
     }
   }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessingTaskTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessingTaskTest.java
deleted file mode 100644 (file)
index 7b8b399..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.computation;
-
-import java.io.File;
-import java.io.IOException;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.container.ComputeEngineContainer;
-import org.sonar.server.computation.container.ContainerFactory;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ReportProcessingTaskTest {
-
-  private static final long ANALYSIS_REPORT_DTO_ID = 663l;
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-  @Rule
-  public LogTester logTester = new LogTester();
-
-  ReportQueue queue = mock(ReportQueue.class);
-  ComponentContainer componentContainer = mock(ComponentContainer.class);
-  ContainerFactory containerFactory = mock(ContainerFactory.class);
-  ReportQueue.Item item = new ReportQueue.Item(createAnalysisReportDto(), new File("Don't care"));
-
-  private static AnalysisReportDto createAnalysisReportDto() {
-    AnalysisReportDto res = new AnalysisReportDto();
-    res.setProjectKey("P1").setId(ANALYSIS_REPORT_DTO_ID);
-    return res;
-  }
-
-  ReportProcessingTask underTest = new ReportProcessingTask(queue, item, componentContainer, containerFactory);
-
-  @Test
-  public void creates_container_for_item_run_its_ReportProcessor_and_remove_from_queue() throws IOException {
-    ComputeEngineContainer computeEngineContainer = mock(ComputeEngineContainer.class);
-    when(containerFactory.create(componentContainer, item)).thenReturn(computeEngineContainer);
-
-    ReportProcessor reportProcessor = mock(ReportProcessor.class);
-    when(computeEngineContainer.getComponentByType(ReportProcessor.class)).thenReturn(reportProcessor);
-
-    underTest.run();
-
-    verify(containerFactory).create(componentContainer, item);
-    verify(reportProcessor).process();
-    verify(computeEngineContainer).cleanup();
-    verify(queue).remove(item);
-  }
-
-  @Test
-  public void remove_from_queue_even_if_process_failed() throws IOException {
-    ComputeEngineContainer computeEngineContainer = mock(ComputeEngineContainer.class);
-    when(containerFactory.create(componentContainer, item)).thenReturn(computeEngineContainer);
-
-    ReportProcessor reportProcessor = mock(ReportProcessor.class);
-    when(computeEngineContainer.getComponentByType(ReportProcessor.class)).thenReturn(reportProcessor);
-    doThrow(new IllegalArgumentException("This exception must be silently logged by ReportProcessingTask"))
-      .when(reportProcessor)
-      .process();
-
-    underTest.run();
-
-    verify(containerFactory).create(componentContainer, item);
-    verify(reportProcessor).process();
-    verify(computeEngineContainer).cleanup();
-    verify(queue).remove(item);
-  }
-
-  @Test
-  public void handle_error_during_removal_from_queue() throws Exception {
-    ComputeEngineContainer computeEngineContainer = mock(ComputeEngineContainer.class);
-    when(containerFactory.create(componentContainer, item)).thenReturn(computeEngineContainer);
-
-    ReportProcessor reportProcessor = mock(ReportProcessor.class);
-    when(computeEngineContainer.getComponentByType(ReportProcessor.class)).thenReturn(reportProcessor);
-
-    doThrow(new IllegalStateException("pb")).when(queue).remove(item);
-
-    underTest.run();
-
-    assertThat(logTester.logs()).contains("Failed to remove analysis report " + ANALYSIS_REPORT_DTO_ID + " from queue");
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportProcessorTest.java
deleted file mode 100644 (file)
index 8282194..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.computation;
-
-import com.google.common.collect.ImmutableList;
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import org.apache.commons.lang.RandomStringUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.db.compute.AnalysisReportDto.Status;
-import org.sonar.server.computation.activity.ActivityManager;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.computation.step.ComputationStep;
-import org.sonar.server.computation.step.ComputationSteps;
-import org.sonar.server.computation.step.ReportComputationSteps;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class ReportProcessorTest {
-
-  @Rule
-  public LogTester logTester = new LogTester();
-
-  ComputationStep projectStep1 = mockStep();
-  ComputationStep projectStep2 = mockStep();
-  ComputationSteps steps = mock(ReportComputationSteps.class);
-  ActivityManager activityManager = mock(ActivityManager.class);
-  System2 system = mock(System2.class);
-  CEQueueStatus queueStatus = mock(CEQueueStatus.class);
-  AnalysisReportDto dto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(Status.PENDING);
-  ReportProcessor underTest;
-
-  @Before
-  public void setUp() {
-    underTest = new ReportProcessor(steps, new ReportQueue.Item(dto, new File("Do_not_care")), activityManager, system, queueStatus);
-  }
-
-  @Test
-  public void process_new_project() {
-    logTester.setLevel(LoggerLevel.INFO);
-
-    when(steps.instances()).thenReturn(Arrays.asList(projectStep1, projectStep2));
-
-    underTest.process();
-
-    // report is integrated -> status is set to SUCCESS
-    assertThat(dto.getStatus()).isEqualTo(Status.SUCCESS);
-    assertThat(dto.getFinishedAt()).isNotNull();
-
-    // one info log at the end
-    assertThat(logTester.logs(LoggerLevel.INFO)).hasSize(3);
-//    assertThat(logTester.logs(LoggerLevel.INFO).get(0)).startsWith("Analysis of project P1 (report 1) (done) | time=");
-    assertThat(logTester.logs(LoggerLevel.INFO).get(2)).startsWith("Analysis of project P1 (report 1) total time spent in steps=");
-
-    // execute only the steps supporting the project qualifier
-    verify(projectStep1).execute();
-    verify(projectStep2).execute();
-    verify(activityManager).saveActivity(dto);
-
-    verify(queueStatus).addInProgress();
-    verify(queueStatus).addSuccess(anyLong());
-    verifyNoMoreInteractions(queueStatus);
-  }
-
-  @Test
-  public void debug_logs() {
-    when(steps.instances()).thenReturn(Collections.<ComputationStep>emptyList());
-    logTester.setLevel(LoggerLevel.DEBUG);
-
-    underTest.process();
-
-    assertThat(logTester.logs(LoggerLevel.DEBUG)).isNotEmpty();
-  }
-
-  @Test
-  public void fail_if_step_throws_error() {
-    String errorMessage = "Failed to unzip";
-    when(steps.instances()).thenReturn(ImmutableList.of(projectStep1));
-    doThrow(new IllegalStateException(errorMessage)).when(projectStep1).execute();
-
-    try {
-      underTest.process();
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).isEqualTo(errorMessage);
-      assertThat(dto.getStatus()).isEqualTo(Status.FAILED);
-      assertThat(dto.getFinishedAt()).isNotNull();
-
-      verify(queueStatus).addInProgress();
-      verify(queueStatus).addError(anyLong());
-      verifyNoMoreInteractions(queueStatus);
-    }
-  }
-
-  @Test
-  public void step_error() {
-    when(steps.instances()).thenReturn(Collections.singleton(projectStep1));
-    doThrow(new IllegalStateException("pb")).when(projectStep1).execute();
-
-    try {
-      underTest.process();
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).isEqualTo("pb");
-      assertThat(dto.getStatus()).isEqualTo(Status.FAILED);
-      assertThat(dto.getFinishedAt()).isNotNull();
-
-      verify(queueStatus).addInProgress();
-      verify(queueStatus).addError(anyLong());
-      verifyNoMoreInteractions(queueStatus);
-    }
-  }
-
-  private ComputationStep mockStep() {
-    ComputationStep step = mock(ComputationStep.class);
-    when(step.getDescription()).thenReturn(RandomStringUtils.randomAscii(5));
-    return step;
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueCleanerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueCleanerTest.java
deleted file mode 100644 (file)
index 38a5875..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.computation;
-
-import org.junit.Test;
-import org.sonar.api.platform.ServerUpgradeStatus;
-
-import static org.mockito.Mockito.*;
-
-public class ReportQueueCleanerTest {
-
-  ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class);
-  ReportQueue queue = mock(ReportQueue.class);
-  ReportQueueCleaner underTest = new ReportQueueCleaner(serverUpgradeStatus, queue);
-
-  @Test
-  public void reset_reports_on_restart() {
-    underTest.start();
-    verify(queue).resetToPendingStatus();
-    underTest.stop();
-  }
-
-  @Test
-  public void delete_all_reports_on_upgrade() {
-    when(serverUpgradeStatus.isUpgraded()).thenReturn(Boolean.TRUE);
-    underTest.start();
-    verify(queue).clear();
-    underTest.stop();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportQueueTest.java
deleted file mode 100644 (file)
index d54d47e..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.computation;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.Settings;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.process.ProcessProperties;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-import static org.sonar.db.compute.AnalysisReportDto.Status.PENDING;
-import static org.sonar.db.compute.AnalysisReportDto.Status.WORKING;
-
-@Category(DbTests.class)
-public class ReportQueueTest {
-
-  static final long NOW = 1_500_000_000_000L;
-
-  System2 system = mock(System2.class);
-
-  @Rule
-  public DbTester db = DbTester.create(system);
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  DbClient dbClient = db.getDbClient();
-
-  Settings settings = new Settings();
-  CEQueueStatus queueStatus = mock(CEQueueStatus.class);
-  File dataDir;
-  ReportQueue underTest;
-
-  @Before
-  public void setUp() throws Exception {
-    dataDir = temp.newFolder();
-    settings.setProperty(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath());
-    when(system.now()).thenReturn(NOW);
-
-    underTest = new ReportQueue(dbClient, settings, queueStatus);
-  }
-
-  @Test
-  public void starts_initializes_count_of_pending_reports() {
-    underTest.add("P1", "Project 1", generateData());
-    underTest.add("P2", "Project 2", generateData());
-    underTest.add("P3", "Project 3", generateData());
-
-    underTest.start();
-
-    verify(queueStatus).initPendingCount(3);
-    verifyNoMoreInteractions(queueStatus);
-  }
-
-  @Test
-  public void add_report_to_queue() {
-    // must:
-    // 1. insert metadata in db
-    // 2. copy report content to directory /data/analysis
-    ReportQueue.Item item = underTest.add("P1", "Project 1", generateData());
-
-    assertThat(item).isNotNull();
-    assertThat(item.zipFile).isFile().exists().hasContent("some data").hasParent(new File(dataDir, "analysis"));
-    assertThat(item.dto.getUuid()).isNotEmpty();
-    assertThat(item.dto.getId()).isGreaterThan(0L);
-
-    List<AnalysisReportDto> reports = dbClient.analysisReportDao().selectByProjectKey(db.getSession(), "P1");
-    assertThat(reports).hasSize(1);
-    AnalysisReportDto report = reports.get(0);
-
-    assertThat(reports).hasSize(1);
-    assertThat(report.getStatus()).isEqualTo(PENDING);
-    assertThat(report.getProjectKey()).isEqualTo("P1");
-    assertThat(report.getProjectName()).isEqualTo("Project 1");
-    assertThat(report.getUuid()).isNotEmpty();
-    assertThat(report.getId()).isGreaterThan(0L);
-    assertThat(report.getCreatedAt()).isEqualTo(NOW);
-    assertThat(report.getUpdatedAt()).isEqualTo(NOW);
-    assertThat(report.getStartedAt()).isNull();
-    assertThat(report.getFinishedAt()).isNull();
-
-    assertThat(FileUtils.listFiles(analysisDir(), new String[]{"zip"}, false)).hasSize(1);
-  }
-
-  @Test
-  public void pop_pending_items_in_fifo_order() {
-    underTest.add("P1", "Project 1", generateData());
-    underTest.add("P2", "Project 2", generateData());
-    underTest.add("P3", "Project 3", generateData());
-
-    ReportQueue.Item item = underTest.pop();
-    assertThat(item.dto.getProjectKey()).isEqualTo("P1");
-    assertThat(item.zipFile).exists().isFile().hasExtension("zip");
-
-    // status changed from PENDING to WORKING
-    assertThat(item.dto.getStatus()).isEqualTo(WORKING);
-
-    assertThat(underTest.pop().dto.getProjectKey()).isEqualTo("P2");
-    assertThat(underTest.pop().dto.getProjectKey()).isEqualTo("P3");
-
-    // queue is empty
-    assertThat(underTest.pop()).isNull();
-
-    // items are still in db, but in WORKING status
-    List<AnalysisReportDto> reports = underTest.all();
-    assertThat(reports).hasSize(3);
-    assertThat(reports).extracting("status").containsOnly(WORKING);
-  }
-
-  @Test
-  public void remove() {
-    ReportQueue.Item item = underTest.add("P1", "Project 1", generateData());
-    assertThat(db.countRowsOfTable("analysis_reports")).isEqualTo(1);
-
-    underTest.remove(item);
-    assertThat(db.countRowsOfTable("analysis_reports")).isEqualTo(0);
-    assertThat(item.zipFile).doesNotExist();
-  }
-
-  @Test
-  public void do_not_pop_corrupted_item() {
-    ReportQueue.Item item = underTest.add("P1", "Project 1", generateData());
-
-    // emulate corruption: file is missing on FS
-    FileUtils.deleteQuietly(item.zipFile);
-
-    assertThat(underTest.pop()).isNull();
-
-    // table sanitized
-    assertThat(db.countRowsOfTable("analysis_reports")).isEqualTo(0);
-  }
-
-  @Test
-  public void clear() {
-    underTest.add("P1", "Project 1", generateData());
-    underTest.add("P2", "Project 2", generateData());
-    assertThat(analysisDir()).exists().isDirectory();
-
-    underTest.clear();
-
-    assertThat(db.countRowsOfTable("analysis_reports")).isEqualTo(0);
-    assertThat(analysisDir()).doesNotExist();
-  }
-
-  @Test
-  public void clear_do_not_fail_when_directory_do_not_exist() {
-    underTest.clear();
-    underTest.clear();
-  }
-
-  @Test
-  public void reset_to_pending_status() {
-    // 2 pending
-    underTest.add("P1", "Project 1", generateData());
-    underTest.add("P2", "Project 2", generateData());
-
-    // pop 1 -> 1 pending and 1 working
-    ReportQueue.Item workingItem = underTest.pop();
-    assertThat(workingItem.dto.getStatus()).isEqualTo(WORKING);
-    assertThat(underTest.all()).extracting("status").contains(PENDING, WORKING);
-
-    underTest.resetToPendingStatus();
-    assertThat(underTest.all()).extracting("status").containsOnly(PENDING).hasSize(2);
-
-  }
-
-  private InputStream generateData() {
-    return IOUtils.toInputStream("some data");
-  }
-
-  private File analysisDir() {
-    return new File(dataDir, "analysis");
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ReportSubmitterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ReportSubmitterTest.java
new file mode 100644 (file)
index 0000000..f9f3948
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.computation;
+
+import org.apache.commons.io.IOUtils;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ReportSubmitterTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  CeQueue queue = mock(CeQueue.class);
+  ReportFiles reportFiles = mock(ReportFiles.class);
+  ComponentService componentService = mock(ComponentService.class);
+  ReportSubmitter underTest = new ReportSubmitter(queue, userSession, reportFiles, componentService);
+
+  @Test
+  public void submit_a_report_on_existing_project() {
+    when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit("TASK_1"));
+    userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+    when(componentService.getNullableByKey("MY_PROJECT")).thenReturn(new ComponentDto().setUuid("P1"));
+
+    underTest.submit("MY_PROJECT", "My Project", IOUtils.toInputStream("{binary}"));
+
+    verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
+      @Override
+      protected boolean matchesSafely(CeTaskSubmit submit) {
+        return submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals("P1") &&
+          submit.getUuid().equals("TASK_1");
+      }
+
+      @Override
+      public void describeTo(Description description) {
+
+      }
+    }));
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/activity/ActivityManagerTest.java
deleted file mode 100644 (file)
index c5b0ef2..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.computation.activity;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.ActivityService;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-@Category(DbTests.class)
-public class ActivityManagerTest {
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
-  ArgumentCaptor<Activity> activityArgumentCaptor = ArgumentCaptor.forClass(Activity.class);
-
-  AnalysisReportDto reportDto = AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
-
-  ActivityService activityService = mock(ActivityService.class);
-  ActivityManager underTest;
-
-  @Before
-  public void setup() {
-    dbTester.truncateTables();
-    underTest = new ActivityManager(activityService, dbTester.getDbClient());
-  }
-
-  @Test
-  public void process_existing_project() {
-    dbTester.prepareDbUnit(getClass(), "shared.xml");
-
-    underTest.saveActivity(reportDto);
-
-    verify(activityService).save(activityArgumentCaptor.capture());
-
-    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
-    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectName", "Project 1");
-    assertThat(activityArgumentCaptor.getValue().getData().get("projectUuid")).isEqualTo("ABCD");
-  }
-
-  @Test
-  public void process_new_project() {
-    underTest.saveActivity(reportDto);
-
-    // execute only the steps supporting the project qualifier
-    verify(activityService).save(activityArgumentCaptor.capture());
-
-    assertThat(activityArgumentCaptor.getValue().getType()).isEqualTo(Activity.Type.ANALYSIS_REPORT);
-    assertThat(activityArgumentCaptor.getValue().getAction()).isEqualTo("LOG_ANALYSIS_REPORT");
-    assertThat(activityArgumentCaptor.getValue().getData()).containsEntry("projectKey", "P1");
-  }
-
-}
index 1ff92d01e632be565a4feaabf30813d2984889ea..3d4656b63c1cd30c2a2f77caefdcfc30d9547bfa 100644 (file)
@@ -27,7 +27,7 @@ import java.util.List;
 import javax.annotation.Nullable;
 import org.junit.Test;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeTask;
 import org.sonar.server.computation.step.ComputationStep;
 
 import static com.google.common.base.Predicates.notNull;
@@ -36,15 +36,15 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
 public class ReportComputeEngineContainerPopulatorTest {
-  private ReportQueue.Item item = mock(ReportQueue.Item.class);
-  private ReportComputeEngineContainerPopulator underTest = new ReportComputeEngineContainerPopulator(item);
+  private CeTask task = mock(CeTask.class);
+  private ReportComputeEngineContainerPopulator underTest = new ReportComputeEngineContainerPopulator(task);
 
   @Test
   public void item_is_added_to_the_container() {
     AddedObjectsRecorderComputeEngineContainer container = new AddedObjectsRecorderComputeEngineContainer();
     underTest.populateContainer(container);
 
-    assertThat(container.added).contains(item);
+    assertThat(container.added).contains(task);
   }
 
   @Test
index 0b62598f3d0ebd896862aa75ed8b9b9e252264f1..18e338d7ebc5c093105b840fbf8a9158f2e76ff2 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.computation.monitoring;
 
 import org.junit.Test;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeQueue;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
@@ -34,7 +34,7 @@ public class ComputeEngineQueueMonitorTest {
   private static final long SUCCESS_COUNT = 13;
   private static final long PROCESSING_TIME = 987;
 
-  private ComputeEngineQueueMonitor underTest = new ComputeEngineQueueMonitor(new DumbCEQueueStatus(), mock(ReportQueue.class));
+  private ComputeEngineQueueMonitor underTest = new ComputeEngineQueueMonitor(new DumbCEQueueStatus(), mock(CeQueue.class));
 
   @Test
   public void name_is_ComputeEngineQueue() {
index b35a139a4f8e22cbf7c1c4c97f16fe9241c4737b..65616a7bde047229dc48148a463fcf9c38a7ffdd 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Set;
 import org.junit.Test;
 import org.picocontainer.ComponentAdapter;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.CeTask;
 import org.sonar.server.computation.container.ComputeEngineContainerImpl;
 import org.sonar.server.computation.container.ReportComputeEngineContainerPopulator;
 import org.sonar.server.computation.container.StepsExplorer;
@@ -51,7 +51,7 @@ public class ComputationStepsTest {
 
   @Test
   public void all_steps_from_package_step_are_present_in_container() {
-    ComputeEngineContainerImpl ceContainer = new ComputeEngineContainerImpl(new ComponentContainer(), new ReportComputeEngineContainerPopulator(mock(ReportQueue.Item.class)));
+    ComputeEngineContainerImpl ceContainer = new ComputeEngineContainerImpl(new ComponentContainer(), new ReportComputeEngineContainerPopulator(mock(CeTask.class)));
 
     Set<String> stepsCanonicalNames = StepsExplorer.retrieveStepPackageStepsCanonicalNames();
 
index 1d4371b9e93b9d15bafe8ec3ca2b8b28d1934b41..28923478d00a91cbb21a729249d8552ff0ef90c4 100644 (file)
  */
 package org.sonar.server.computation.step;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.utils.internal.JUnitTempFolder;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
 public class ReportExtractionStepTest {
-
-  @Rule
-  public JUnitTempFolder tempFolder = new JUnitTempFolder();
-  @Rule
-  public LogTester logTester = new LogTester().setLevel(LoggerLevel.INFO);
-
-  private MutableBatchReportDirectoryHolder reportDirectoryHolder = mock(MutableBatchReportDirectoryHolder.class);
-  private AnalysisReportDto dto = newDefaultReport();
-  private ArgumentCaptor<File> fileCaptor = ArgumentCaptor.forClass(File.class);
-
-  @Test
-  public void fail_if_corrupted_zip() throws Exception {
-    File zip = tempFolder.newFile();
-    FileUtils.write(zip, "not a file");
-
-    ReportExtractionStep underTest = new ReportExtractionStep(new ReportQueue.Item(dto, zip), tempFolder, reportDirectoryHolder);
-
-    try {
-      underTest.execute();
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).startsWith("Fail to unzip " + zip.getAbsolutePath() + " into ");
-    }
-    verifyNoMoreInteractions(reportDirectoryHolder);
-  }
-
-  @Test
-  public void verify_zip_decompression() throws URISyntaxException, IOException {
-    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
-
-    verify(reportDirectoryHolder).setDirectory(fileCaptor.capture());
-    verifyNoMoreInteractions(reportDirectoryHolder);
-
-    File createDir = fileCaptor.getValue();
-    assertThat(createDir.exists()).isTrue();
-    assertThat(createDir.isDirectory()).isTrue();
-    verifyFile(createDir, "1.txt", "1\n");
-    verifyFile(createDir, "2.txt", "2\n");
-    File subDir1 = verifyDir(createDir, "subdir1");
-    verifyFile(subDir1, "3.txt", "3\n");
-    verifyFile(subDir1, "4.txt", "4\n");
-    File subDir2 = verifyDir(createDir, "subdir2");
-    verifyFile(subDir2, "5.txt", "5\n");
-    File subdir3 = verifyDir(subDir2, "subdir3");
-    verifyFile(subdir3, "6.txt", "6\n");
-  }
-
-  @Test
-  public void verify_show_log_at_DEBUG_level() throws URISyntaxException {
-    logTester.setLevel(LoggerLevel.DEBUG);
-
-    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
-
-    List<String> logs = logTester.logs();
-    assertThat(logs).hasSize(1);
-    String log = logs.get(0);
-    assertThat(log.startsWith("Report extracted | size=")).isTrue();
-    assertThat(log.contains(" | project=P1 | time=")).isTrue();
-  }
-
-  private File demoZipFile() throws URISyntaxException {
-    return new File(getClass().getResource(getClass().getSimpleName() + "/" + "demozip.zip").toURI());
-  }
-
-  @Test
-  public void no_log_at_INFO_level() throws URISyntaxException {
-    logTester.setLevel(LoggerLevel.INFO);
-
-    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
-
-    assertThat(logTester.logs()).isEmpty();
-  }
-
-  private File verifyDir(File dir, String subDir) {
-    File file = new File(dir, subDir);
-    assertThat(file.exists()).isTrue();
-    assertThat(file.isDirectory()).isTrue();
-    return file;
-  }
-
-  private void verifyFile(File dir, String filename, String content) throws IOException {
-    File file = new File(dir, filename);
-    assertThat(file.exists()).isTrue();
-    assertThat(file.isDirectory()).isFalse();
-    assertThat(IOUtils.toString(new FileInputStream(file), "UTF-8")).isEqualTo(content);
-  }
-
-  private static AnalysisReportDto newDefaultReport() {
-    return AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
-  }
+  //
+  // @Rule
+  // public JUnitTempFolder tempFolder = new JUnitTempFolder();
+  // @Rule
+  // public LogTester logTester = new LogTester().setLevel(LoggerLevel.INFO);
+  //
+  // private MutableBatchReportDirectoryHolder reportDirectoryHolder = mock(MutableBatchReportDirectoryHolder.class);
+  // private AnalysisReportDto dto = newDefaultReport();
+  // private ArgumentCaptor<File> fileCaptor = ArgumentCaptor.forClass(File.class);
+  //
+  // @Test
+  // public void fail_if_corrupted_zip() throws Exception {
+  // File zip = tempFolder.newFile();
+  // FileUtils.write(zip, "not a file");
+  //
+  // ReportExtractionStep underTest = new ReportExtractionStep(reportFiles, new ReportQueue.Item(dto, zip), tempFolder,
+  // reportDirectoryHolder);
+  //
+  // try {
+  // underTest.execute();
+  // fail();
+  // } catch (IllegalStateException e) {
+  // assertThat(e.getMessage()).startsWith("Fail to unzip " + zip.getAbsolutePath() + " into ");
+  // }
+  // verifyNoMoreInteractions(reportDirectoryHolder);
+  // }
+  //
+  // @Test
+  // public void verify_zip_decompression() throws URISyntaxException, IOException {
+  // new ReportExtractionStep(reportFiles, new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+  //
+  // verify(reportDirectoryHolder).setDirectory(fileCaptor.capture());
+  // verifyNoMoreInteractions(reportDirectoryHolder);
+  //
+  // File createDir = fileCaptor.getValue();
+  // assertThat(createDir.exists()).isTrue();
+  // assertThat(createDir.isDirectory()).isTrue();
+  // verifyFile(createDir, "1.txt", "1\n");
+  // verifyFile(createDir, "2.txt", "2\n");
+  // File subDir1 = verifyDir(createDir, "subdir1");
+  // verifyFile(subDir1, "3.txt", "3\n");
+  // verifyFile(subDir1, "4.txt", "4\n");
+  // File subDir2 = verifyDir(createDir, "subdir2");
+  // verifyFile(subDir2, "5.txt", "5\n");
+  // File subdir3 = verifyDir(subDir2, "subdir3");
+  // verifyFile(subdir3, "6.txt", "6\n");
+  // }
+  //
+  // @Test
+  // public void verify_show_log_at_DEBUG_level() throws URISyntaxException {
+  // logTester.setLevel(LoggerLevel.DEBUG);
+  //
+  // new ReportExtractionStep(reportFiles, new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+  //
+  // List<String> logs = logTester.logs();
+  // assertThat(logs).hasSize(1);
+  // String log = logs.get(0);
+  // assertThat(log.startsWith("Report extracted | size=")).isTrue();
+  // assertThat(log.contains(" | project=P1 | time=")).isTrue();
+  // }
+  //
+  // private File demoZipFile() throws URISyntaxException {
+  // return new File(getClass().getResource(getClass().getSimpleName() + "/" + "demozip.zip").toURI());
+  // }
+  //
+  // @Test
+  // public void no_log_at_INFO_level() throws URISyntaxException {
+  // logTester.setLevel(LoggerLevel.INFO);
+  //
+  // new ReportExtractionStep(reportFiles, new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+  //
+  // assertThat(logTester.logs()).isEmpty();
+  // }
+  //
+  // private File verifyDir(File dir, String subDir) {
+  // File file = new File(dir, subDir);
+  // assertThat(file.exists()).isTrue();
+  // assertThat(file.isDirectory()).isTrue();
+  // return file;
+  // }
+  //
+  // private void verifyFile(File dir, String filename, String content) throws IOException {
+  // File file = new File(dir, filename);
+  // assertThat(file.exists()).isTrue();
+  // assertThat(file.isDirectory()).isFalse();
+  // assertThat(IOUtils.toString(new FileInputStream(file), "UTF-8")).isEqualTo(content);
+  // }
+  //
+  // private static AnalysisReportDto newDefaultReport() {
+  // return AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
+  // }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeSubmitWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeSubmitWsActionTest.java
new file mode 100644 (file)
index 0000000..deb1921
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.computation.ws;
+
+import java.io.InputStream;
+import org.junit.Test;
+import org.sonar.core.util.Protobuf;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.server.computation.CeTask;
+import org.sonar.server.computation.ReportProcessingScheduler;
+import org.sonar.server.computation.ReportSubmitter;
+import org.sonar.server.plugins.MimeTypes;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.JsonAssert;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class CeSubmitWsActionTest {
+
+  ReportSubmitter reportSubmitter = mock(ReportSubmitter.class);
+  ReportProcessingScheduler reportProcessingScheduler = mock(ReportProcessingScheduler.class);
+  CeSubmitWsAction underTest = new CeSubmitWsAction(reportSubmitter, reportProcessingScheduler);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void submit_task_to_the_queue_and_ask_for_immediate_processing() {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", "robert");
+    when(reportSubmitter.submit(eq("my_project"), eq("My Project"), any(InputStream.class))).thenReturn(task);
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("projectName", "My Project")
+      .setParam("report", "{binary}")
+      .setMediaType(MimeTypes.PROTOBUF)
+      .setMethod("POST")
+      .execute();
+
+    verify(reportSubmitter).submit(eq("my_project"), eq("My Project"), any(InputStream.class));
+    verify(reportProcessingScheduler).startAnalysisTaskNow();
+
+    // verify the protobuf response
+    WsCe.SubmitResponse submitResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.SubmitResponse.PARSER);
+    assertThat(submitResponse.getTaskId()).isEqualTo("TASK_1");
+    assertThat(submitResponse.getProjectId()).isEqualTo("PROJECT_1");
+  }
+
+  @Test
+  public void test_response_example() {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", "robert");
+    when(reportSubmitter.submit(eq("my_project"), eq("My Project"), any(InputStream.class))).thenReturn(task);
+
+    TestResponse wsResponse = tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("projectName", "My Project")
+      .setParam("report", "{binary}")
+      .setMediaType(MimeTypes.JSON)
+      .setMethod("POST")
+      .execute();
+
+    JsonAssert.assertJson(tester.getDef().responseExampleAsString()).isSimilarTo(wsResponse.getInput());
+  }
+
+  /**
+   * If project name is not specified, then name is the project key
+   */
+  @Test
+  public void project_name_is_optional() {
+    CeTask task = new CeTask("TASK_1", CeTaskTypes.REPORT, "PROJECT_1", "robert");
+    when(reportSubmitter.submit(eq("my_project"), eq("my_project"), any(InputStream.class))).thenReturn(task);
+
+    tester.newRequest()
+      .setParam("projectKey", "my_project")
+      .setParam("report", "{binary}")
+      .setMediaType(MimeTypes.PROTOBUF)
+      .setMethod("POST")
+      .execute();
+
+    verify(reportSubmitter).submit(eq("my_project"), eq("my_project"), any(InputStream.class));
+
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeTaskWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeTaskWsActionTest.java
new file mode 100644 (file)
index 0000000..a07fb41
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.computation.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.util.Protobuf;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.ce.CeTaskTypes;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.plugins.MimeTypes;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CeTaskWsActionTest {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+  ComponentService componentService = mock(ComponentService.class);
+  CeWsTaskFormatter formatter = new CeWsTaskFormatter(componentService);
+  CeTaskWsAction underTest = new CeTaskWsAction(dbTester.getDbClient(), formatter, userSession);
+  WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void task_is_in_queue() throws Exception {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    ComponentDto project = new ComponentDto().setUuid("PROJECT_1").setName("Project One").setKey("P1");
+    when(componentService.getNonNullByUuid("PROJECT_1")).thenReturn(project);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setUuid("TASK_1");
+    queueDto.setComponentUuid(project.uuid());
+    queueDto.setStatus(CeQueueDto.Status.PENDING);
+    queueDto.setSubmitterLogin("john");
+    dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
+    dbTester.getSession().commit();
+
+    TestResponse wsResponse = tester.newRequest()
+      .setMediaType(MimeTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+
+    // verify the protobuf response
+    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
+    assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1");
+    assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.PENDING);
+    assertThat(taskResponse.getTask().getSubmitterLogin()).isEqualTo("john");
+    assertThat(taskResponse.getTask().getComponentId()).isEqualTo(project.uuid());
+    assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(project.key());
+    assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name());
+    assertThat(taskResponse.getTask().hasExecutionTimeMs()).isFalse();
+  }
+
+  @Test
+  public void task_is_archived() throws Exception {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    ComponentDto project = new ComponentDto().setUuid("PROJECT_1").setName("Project One").setKey("P1");
+    when(componentService.getNonNullByUuid("PROJECT_1")).thenReturn(project);
+
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setTaskType(CeTaskTypes.REPORT);
+    queueDto.setUuid("TASK_1");
+    queueDto.setComponentUuid(project.uuid());
+    CeActivityDto activityDto = new CeActivityDto(queueDto);
+    activityDto.setStatus(CeActivityDto.Status.FAILED);
+    activityDto.setExecutionTimeMs(500L);
+    dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
+    dbTester.getSession().commit();
+
+    TestResponse wsResponse = tester.newRequest()
+      .setMediaType(MimeTypes.PROTOBUF)
+      .setParam("id", "TASK_1")
+      .execute();
+
+    // verify the protobuf response
+    WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
+    assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1");
+    assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+    assertThat(taskResponse.getTask().getComponentId()).isEqualTo(project.uuid());
+    assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(project.key());
+    assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name());
+    assertThat(taskResponse.getTask().getExecutionTimeMs()).isEqualTo(500L);
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void task_not_found() throws Exception {
+    userSession.setGlobalPermissions(UserRole.ADMIN);
+
+    tester.newRequest()
+      .setParam("id", "DOES_NOT_EXIST")
+      .execute();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/CeWsTest.java
new file mode 100644 (file)
index 0000000..7dcf0f5
--- /dev/null
@@ -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.computation.ws;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.computation.ReportProcessingScheduler;
+import org.sonar.server.computation.ReportSubmitter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class CeWsTest {
+
+  @Test
+  public void define() throws Exception {
+    CeWsAction wsAction = new CeSubmitWsAction(mock(ReportSubmitter.class), mock(ReportProcessingScheduler.class));
+
+    CeWs ws = new CeWs(wsAction);
+    WebService.Context context = mock(WebService.Context.class, Mockito.RETURNS_DEEP_STUBS);
+    ws.define(context);
+
+    assertThat(context.controller("api/ce")).isNotNull();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComputationWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComputationWsTest.java
deleted file mode 100644 (file)
index b40aec6..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.junit.Test;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.activity.index.ActivityIndex;
-import org.sonar.server.computation.ReportProcessingScheduler;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.ws.WsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class ComputationWsTest {
-
-  WsTester ws = new WsTester(new ComputationWs(
-    new QueueAction(mock(ReportQueue.class)),
-    new SubmitReportAction(mock(ReportQueue.class), mock(ReportProcessingScheduler.class), mock(UserSession.class), mock(CEQueueStatus.class)),
-    new HistoryAction(mock(ActivityIndex.class), mock(UserSession.class))));
-
-  @Test
-  public void define() {
-    WebService.Controller controller = ws.controller("api/computation");
-
-    assertThat(controller).isNotNull();
-    assertThat(controller.description()).isNotEmpty();
-    assertThat(controller.actions()).hasSize(3);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/HistoryActionMediumTest.java
deleted file mode 100644 (file)
index f971c31..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.computation.ws;
-
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.activity.Activity;
-import org.sonar.server.activity.ActivityService;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.tester.ServerTester;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsTester;
-
-import java.util.Date;
-
-/**
- * TODO replace this medium test by a small test
- */
-public class HistoryActionMediumTest {
-
-  @ClassRule
-  public static ServerTester tester = new ServerTester().withStartupTasks().withEsIndexes();
-  @Rule
-  public UserSessionRule userSessionRule = UserSessionRule.forServerTester(tester);
-
-  HistoryAction sut;
-  ActivityService activityService;
-
-  @Before
-  public void setUp() {
-    tester.clearDbAndIndexes();
-    sut = tester.get(HistoryAction.class);
-    activityService = tester.get(ActivityService.class);
-  }
-
-  @Test
-  public void search() throws Exception {
-    Activity activity1 = new Activity();
-    activity1.setType(Activity.Type.ANALYSIS_REPORT);
-    activity1.setAction("LOG_ANALYSIS_REPORT");
-    activity1.setData("projectKey", "P1");
-    activity1.setData("projectName", "POne");
-    activity1.setData("projectUuid", "U1");
-    activity1.setData("status", AnalysisReportDto.Status.SUCCESS);
-    activity1.setData("submittedAt", new Date());
-    activityService.save(activity1);
-
-    Activity activity2 = new Activity();
-    activity2.setType(Activity.Type.ANALYSIS_REPORT);
-    activity2.setAction("LOG_ANALYSIS_REPORT");
-    activity2.setData("projectKey", "P2");
-    activity2.setData("projectName", "PTwo");
-    activity2.setData("projectUuid", "U2");
-    activity2.setData("status", AnalysisReportDto.Status.FAILED);
-    activity2.setData("submittedAt", new Date());
-    activityService.save(activity2);
-
-    userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-
-    WsTester.TestRequest request = tester.wsTester().newGetRequest("api/computation", "history");
-    request.execute().assertJson(getClass(), "list_history_reports.json");
-  }
-
-  @Test(expected = ForbiddenException.class)
-  public void requires_admin_right() throws Exception {
-    WsTester.TestRequest request = tester.wsTester().newGetRequest("api/computation", "history");
-    request.execute();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/IsQueueEmptyWsTest.java
deleted file mode 100644 (file)
index 034687f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.computation.ws;
-
-import com.google.common.collect.Lists;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class IsQueueEmptyWsTest {
-
-  IsQueueEmptyWs.IsQueueEmptyAction underTest;
-  ReportQueue queue;
-  Response response;
-
-  @Before
-  public void before() {
-    queue = mock(ReportQueue.class);
-    underTest = new IsQueueEmptyWs.IsQueueEmptyAction(queue);
-
-    response = mock(Response.class);
-    when(response.stream()).thenReturn(new FakeStream());
-  }
-
-  @Test
-  public void send_true_when_queue_is_empty() throws Exception {
-    when(queue.all()).thenReturn(new ArrayList<AnalysisReportDto>());
-
-    underTest.handle(mock(Request.class), response);
-
-    assertThat(response.stream().toString()).isEqualTo("true");
-  }
-
-  @Test
-  public void send_false_when_queue_is_not_empty() throws Exception {
-    when(queue.all()).thenReturn(Lists.newArrayList(AnalysisReportDto.newForTests(1L)));
-
-    underTest.handle(mock(Request.class), response);
-
-    assertThat(response.stream().toString()).isEqualTo("false");
-  }
-
-  private class FakeStream implements Response.Stream {
-    private ByteArrayOutputStream stream;
-
-    private FakeStream() {
-      this.stream = new ByteArrayOutputStream();
-    }
-
-    public String toString() {
-      return stream.toString();
-    }
-
-    @Override
-    public Response.Stream setMediaType(String s) {
-      return null;
-    }
-
-    @Override
-    public Response.Stream setStatus(int httpStatus) {
-      return null;
-    }
-
-    @Override
-    public OutputStream output() {
-      return stream;
-    }
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/QueueActionTest.java
deleted file mode 100644 (file)
index e74d9d1..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.computation.ws;
-
-import com.google.common.collect.Lists;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.ws.WsTester;
-
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.db.compute.AnalysisReportDto.Status.PENDING;
-
-public class QueueActionTest {
-
-  WsTester tester;
-  private ReportQueue queue;
-
-  @Before
-  public void setup() {
-    queue = mock(ReportQueue.class);
-    tester = new WsTester(new ComputationWs(new QueueAction(queue)));
-  }
-
-  @Test
-  public void list_active_reports() throws Exception {
-    AnalysisReportDto report = AnalysisReportDto
-      .newForTests(1L)
-      .setProjectKey("project-key")
-      .setProjectName("Project name")
-      .setStatus(PENDING)
-      .setUuid("PROJECT_UUID")
-      .setCreatedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime())
-      .setStartedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime())
-      .setFinishedAt(DateUtils.parseDateTime("2014-10-13T00:00:00+0200").getTime());
-    List<AnalysisReportDto> reports = Lists.newArrayList(report);
-    when(queue.all()).thenReturn(reports);
-
-    WsTester.TestRequest request = tester.newGetRequest(ComputationWs.ENDPOINT, "queue");
-    request.execute().assertJson(getClass(), "list_queue_reports.json");
-  }
-
-  @Test
-  public void define() {
-    assertThat(tester.controller(ComputationWs.ENDPOINT).action("queue")).isNotNull();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/SubmitReportActionTest.java
deleted file mode 100644 (file)
index 18f8fdf..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.computation.ws;
-
-import java.io.InputStream;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.server.computation.ReportProcessingScheduler;
-import org.sonar.server.computation.ReportQueue;
-import org.sonar.server.computation.monitoring.CEQueueStatus;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SubmitReportActionTest {
-
-  @Rule
-  public UserSessionRule userSessionRule = UserSessionRule.standalone();
-
-  ReportProcessingScheduler workerLauncher = mock(ReportProcessingScheduler.class);
-  CEQueueStatus queueStatus = mock(CEQueueStatus.class);
-  ReportQueue queue = mock(ReportQueue.class);
-  WsTester wsTester;
-  SubmitReportAction underTest;
-
-  @Before
-  public void before() {
-    underTest = new SubmitReportAction(queue, workerLauncher, userSessionRule, queueStatus);
-    wsTester = new WsTester(new ComputationWs(underTest));
-  }
-
-  @Test
-  public void define_metadata() {
-    WebService.Context context = new WebService.Context();
-    WebService.NewController controller = context.createController("api/computation");
-    underTest.define(controller);
-    controller.done();
-
-    WebService.Action action = context.controller("api/computation").action("submit_report");
-    assertThat(action).isNotNull();
-    assertThat(action.params()).hasSize(3);
-  }
-
-  @Test
-  public void add_element_to_queue_and_launch_analysis_task() throws Exception {
-    userSessionRule.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
-    AnalysisReportDto dto = mock(AnalysisReportDto.class);
-    when(dto.getId()).thenReturn(42L);
-    when(queue.add(any(String.class), any(String.class), any(InputStream.class))).thenReturn(new ReportQueue.Item(dto, null));
-
-    WsTester.TestRequest request = wsTester
-      .newPostRequest(ComputationWs.ENDPOINT, "submit_report")
-      .setParam(SubmitReportAction.PARAM_PROJECT_KEY, "P1")
-      .setParam(SubmitReportAction.PARAM_PROJECT_NAME, "Project 1")
-      .setParam(SubmitReportAction.PARAM_REPORT_DATA, null);
-    WsTester.Result response = request.execute();
-
-    verify(queue).add(eq("P1"), eq("Project 1"), any(InputStream.class));
-    verify(workerLauncher).startAnalysisTaskNow();
-    verify(queueStatus).addReceived();
-    assertThat(response.outputAsString()).isEqualTo("{\"key\":\"42\"}");
-  }
-
-  @Test(expected = ForbiddenException.class)
-  public void requires_scan_permission() throws Exception {
-    userSessionRule.setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);
-
-    WsTester.TestRequest request = wsTester
-      .newPostRequest(ComputationWs.ENDPOINT, "submit_report")
-      .setParam(SubmitReportAction.PARAM_PROJECT_KEY, "P1")
-      .setParam(SubmitReportAction.PARAM_PROJECT_NAME, "Project 1")
-      .setParam(SubmitReportAction.PARAM_REPORT_DATA, null);
-    request.execute();
-
-  }
-}
index 3405e132459d8e80cab675a8e2ad564886288cab..5d844b9757e1e4a51ab8db5dfa3f95863262892e 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.base.Throwables;
 import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.commons.io.IOUtils;
 import org.sonar.api.server.ws.internal.ValidatingRequest;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -40,7 +41,11 @@ public class TestRequest extends ValidatingRequest {
 
   @Override
   protected InputStream readInputStreamParam(String key) {
-    throw new UnsupportedOperationException("Not supported in test yet");
+    String value = readParam(key);
+    if (value == null) {
+      return null;
+    }
+    return IOUtils.toInputStream(value);
   }
 
   @Override
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/HistoryActionMediumTest/list_history_reports.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/HistoryActionMediumTest/list_history_reports.json
deleted file mode 100644 (file)
index caa1808..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "reports": [
-    {
-      "status": "SUCCESS",
-      "projectName": "POne",
-      "projectKey": "P1",
-      "projectUuid": "U1"
-    },
-    {
-      "status": "FAILED",
-      "projectName": "PTwo",
-      "projectKey": "P2",
-      "projectUuid": "U2"
-    }
-  ]
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/QueueActionTest/list_queue_reports.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/ws/QueueActionTest/list_queue_reports.json
deleted file mode 100644 (file)
index 10247f2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "reports": [
-    {
-      "key": 1,
-      "status": "PENDING",
-      "projectName": "Project name",
-      "projectKey": "project-key",
-      "submittedAt": "2014-10-13T00:00:00+0200",
-      "startedAt": "2014-10-13T00:00:00+0200",
-      "finishedAt": "2014-10-13T00:00:00+0200"
-    }
-  ]
-}
index c8ba5db51d7085de0e4b7096125c0f4cfc0b214b..d46065fdecc3f465b1c29ae39bca90c46db81f34 100644 (file)
@@ -39,6 +39,10 @@ class AddScanAndDryRunPermissions < ActiveRecord::Migration
     # -- Role dryRunScan --
     # Anyone
     GroupRole.create(:group_id => nil, :role => 'dryRunScan', :resource_id => nil)
+
+    # -- Role provisioning --
+    # Anyone
+    GroupRole.create(:group_id => nil, :role => 'provisioning', :resource_id => nil)
   end
 
 end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_create_ce_activity.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_create_ce_activity.rb
new file mode 100644 (file)
index 0000000..e2bb4cb
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+#
+# SonarQube 5.2
+#
+class CreateCeActivity < ActiveRecord::Migration
+
+  def self.up
+    create_table 'ce_activity' do |t|
+      t.column 'uuid', :string, :limit => 40, :null => false
+      t.column 'task_type', :string, :limit => 15, :null => false
+      t.column 'component_uuid', :string, :limit => 40, :null => true
+      t.column 'status', :string, :limit => 15, :null => false
+      t.column 'is_last', :boolean, :null => false
+      t.column 'is_last_key', :string, :limit => 55, :null => false
+      t.column 'submitter_login', :string, :limit => 255, :null => true
+      t.column 'submitted_at', :big_integer, :null => false
+      t.column 'started_at', :big_integer, :null => true
+      t.column 'finished_at', :big_integer, :null => true
+      t.column 'created_at', :big_integer, :null => false
+      t.column 'updated_at', :big_integer, :null => false
+      t.column 'execution_time_ms', :big_integer, :null => true
+    end
+    add_index 'ce_activity', 'uuid', :name => 'ce_activity_uuid', :unique => true
+  end
+
+end
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/932_create_ce_queue.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/932_create_ce_queue.rb
new file mode 100644 (file)
index 0000000..e8d0be4
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+#
+# SonarQube 5.2
+#
+class CreateCeQueue < ActiveRecord::Migration
+
+  def self.up
+    create_table 'ce_queue' do |t|
+      t.column 'uuid', :string, :limit => 40, :null => false
+      t.column 'task_type', :string, :limit => 15, :null => false
+      t.column 'component_uuid', :string, :limit => 40, :null => true
+      t.column 'status', :string, :limit => 15, :null => false
+      t.column 'submitter_login', :string, :limit => 255, :null => true
+      t.column 'started_at', :big_integer, :null => true
+      t.column 'created_at', :big_integer, :null => false
+      t.column 'updated_at', :big_integer, :null => false
+    end
+    add_index 'ce_queue', 'uuid', :name => 'ce_queue_uuid', :unique => true
+  end
+
+end
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/933_drop_table_analysis_reports.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/933_drop_table_analysis_reports.rb
new file mode 100644 (file)
index 0000000..36e925b
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+#
+# SonarQube 5.2
+#
+class DropTableAnalysisReports < ActiveRecord::Migration
+
+  def self.up
+    drop_table 'analysis_reports'
+  end
+
+end
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/934_remove_analysis_reports_from_activities.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/934_remove_analysis_reports_from_activities.rb
new file mode 100644 (file)
index 0000000..3c87791
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+#
+# SonarQube 5.2
+#
+class RemoveAnalysisReportsFromActivities < ActiveRecord::Migration
+
+  def self.up
+    execute_java_migration('org.sonar.db.version.v52.RemoveAnalysisReportsFromActivities')
+  end
+
+end
+
index 418703ae7fa86aed49beba4bd06fe2d36979c86a..232d91d4e7e2d80a31a042f74e9735ef4a771053 100644 (file)
@@ -138,7 +138,7 @@ public class ReportPublisher implements Startable {
   void sendOrDumpReport(File report) {
     ProjectDefinition projectDefinition = projectReactor.getRoot();
     String effectiveKey = projectDefinition.getKeyWithBranch();
-    String relativeUrl = "/api/computation/submit_report?projectKey=" + effectiveKey + "&projectName=" + BatchUtils.encodeForUrl(projectDefinition.getName());
+    String relativeUrl = "/api/ce/submit?projectKey=" + effectiveKey + "&projectName=" + BatchUtils.encodeForUrl(projectDefinition.getName());
 
     String dumpDirLocation = settings.getString(DUMP_REPORT_PROP_KEY);
     if (dumpDirLocation == null) {
index 836523abce84ffe8637ea737f739f94bc8620b19..84be626da73df0609091c2d4f27d23f2cc42a784 100644 (file)
@@ -36,7 +36,7 @@ public interface PluginRepository {
   PluginInfo getPluginInfo(String key);
 
   /**
-   * @return the instance of {@link Plugin} for the given plugin key. Never return null.
+   * @return the instance of {@link SonarPlugin} for the given plugin key. Never return null.
    */
   SonarPlugin getPluginInstance(String key);
 
index 7b8b25c6e7314d8c0aeff1a917e5c20570cb9204..53a2809d6190b015b8d51b3930ddcf1e8206100f 100644 (file)
@@ -56,6 +56,16 @@ public class Protobuf {
     }
   }
 
+  public static <MSG extends Message> MSG read(InputStream input, Parser<MSG> parser) {
+    try {
+      return parser.parseFrom(input);
+    } catch (Exception e) {
+      throw ContextException.of("Unable to read message", e);
+    } finally {
+      IOUtils.closeQuietly(input);
+    }
+  }
+
   /**
    * Writes a single message to {@code file}. Existing content is replaced, the message is not
    * appended.
index 99bd33d1eb590ff8e53eb6be3df859bc48182fe7..adb259fbf70920271eda8a897d4d58096bb9690e 100644 (file)
@@ -19,5 +19,8 @@
  */
 package org.sonar.db;
 
+/**
+ * All implementations must be declared in {@link DaoModule}
+ */
 public interface Dao {
 }
index dde96831544badd7f032129e019d8d3eadc2eeac..38536bf226b9d431b450be0bffbbafb6d97c70c7 100644 (file)
@@ -24,13 +24,14 @@ import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.sonar.core.platform.Module;
 import org.sonar.db.activity.ActivityDao;
+import org.sonar.db.ce.CeActivityDao;
+import org.sonar.db.ce.CeQueueDao;
 import org.sonar.db.component.ComponentDao;
 import org.sonar.db.component.ComponentLinkDao;
 import org.sonar.db.component.ResourceDao;
 import org.sonar.db.component.ResourceIndexDao;
 import org.sonar.db.component.ResourceKeyUpdaterDao;
 import org.sonar.db.component.SnapshotDao;
-import org.sonar.db.compute.AnalysisReportDao;
 import org.sonar.db.dashboard.ActiveDashboardDao;
 import org.sonar.db.dashboard.DashboardDao;
 import org.sonar.db.dashboard.WidgetDao;
@@ -74,9 +75,10 @@ public class DaoModule extends Module {
     ActionPlanStatsDao.class,
     ActiveDashboardDao.class,
     ActivityDao.class,
-    AnalysisReportDao.class,
     AuthorDao.class,
     AuthorizationDao.class,
+    CeActivityDao.class,
+    CeQueueDao.class,
     ComponentDao.class,
     ComponentLinkDao.class,
     CustomMeasureDao.class,
index f6471e7388e77e4346bfd31cc44c890ac93335da..1759feb17beeb547efc6e44eba015a7457dc5792 100644 (file)
@@ -23,13 +23,14 @@ import java.util.IdentityHashMap;
 import java.util.Map;
 import javax.annotation.Nullable;
 import org.sonar.db.activity.ActivityDao;
+import org.sonar.db.ce.CeActivityDao;
+import org.sonar.db.ce.CeQueueDao;
 import org.sonar.db.component.ComponentDao;
 import org.sonar.db.component.ComponentLinkDao;
 import org.sonar.db.component.ResourceDao;
 import org.sonar.db.component.ResourceIndexDao;
 import org.sonar.db.component.ResourceKeyUpdaterDao;
 import org.sonar.db.component.SnapshotDao;
-import org.sonar.db.compute.AnalysisReportDao;
 import org.sonar.db.dashboard.ActiveDashboardDao;
 import org.sonar.db.dashboard.DashboardDao;
 import org.sonar.db.dashboard.WidgetDao;
@@ -95,7 +96,8 @@ public class DbClient {
   private final IssueChangeDao issueChangeDao;
   private final ActionPlanDao actionPlanDao;
   private final ActionPlanStatsDao actionPlanStatsDao;
-  private final AnalysisReportDao analysisReportDao;
+  private final CeQueueDao ceQueueDao;
+  private final CeActivityDao ceActivityDao;
   private final DashboardDao dashboardDao;
   private final ActiveDashboardDao activeDashboardDao;
   private final WidgetDao widgetDao;
@@ -148,7 +150,8 @@ public class DbClient {
     issueChangeDao = getDao(map, IssueChangeDao.class);
     actionPlanDao = getDao(map, ActionPlanDao.class);
     actionPlanStatsDao = getDao(map, ActionPlanStatsDao.class);
-    analysisReportDao = getDao(map, AnalysisReportDao.class);
+    ceQueueDao = getDao(map, CeQueueDao.class);
+    ceActivityDao = getDao(map, CeActivityDao.class);
     dashboardDao = getDao(map, DashboardDao.class);
     activeDashboardDao = getDao(map, ActiveDashboardDao.class);
     widgetDao = getDao(map, WidgetDao.class);
@@ -280,8 +283,12 @@ public class DbClient {
     return actionPlanDao;
   }
 
-  public AnalysisReportDao analysisReportDao() {
-    return analysisReportDao;
+  public CeQueueDao ceQueueDao() {
+    return ceQueueDao;
+  }
+
+  public CeActivityDao ceActivityDao() {
+    return ceActivityDao;
   }
 
   public DashboardDao dashboardDao() {
index ea484ad78ef61c6dd0e4491e2916048d37a742ee..5887b49c205e3ccdb3239377aff0c33de5f37242 100644 (file)
@@ -32,6 +32,8 @@ import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.db.activity.ActivityDto;
 import org.sonar.db.activity.ActivityMapper;
+import org.sonar.db.ce.CeActivityMapper;
+import org.sonar.db.ce.CeQueueMapper;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentLinkDto;
 import org.sonar.db.component.ComponentLinkMapper;
@@ -46,8 +48,6 @@ import org.sonar.db.component.SnapshotDto;
 import org.sonar.db.component.SnapshotMapper;
 import org.sonar.db.component.UuidWithProjectUuidDto;
 import org.sonar.db.component.ViewsSnapshotDto;
-import org.sonar.db.compute.AnalysisReportDto;
-import org.sonar.db.compute.AnalysisReportMapper;
 import org.sonar.db.dashboard.ActiveDashboardDto;
 import org.sonar.db.dashboard.ActiveDashboardMapper;
 import org.sonar.db.dashboard.DashboardDto;
@@ -95,6 +95,7 @@ import org.sonar.db.permission.PermissionTemplateUserDto;
 import org.sonar.db.permission.UserWithPermissionDto;
 import org.sonar.db.property.PropertiesMapper;
 import org.sonar.db.property.PropertyDto;
+import org.sonar.db.purge.IdUuidPair;
 import org.sonar.db.purge.PurgeMapper;
 import org.sonar.db.purge.PurgeableSnapshotDto;
 import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
@@ -204,7 +205,7 @@ public class MyBatis {
     confBuilder.loadAlias("ActiveRuleParam", ActiveRuleParamDto.class);
     confBuilder.loadAlias("RequirementMigration", RequirementMigrationDto.class);
     confBuilder.loadAlias("Activity", ActivityDto.class);
-    confBuilder.loadAlias("AnalysisReport", AnalysisReportDto.class);
+    confBuilder.loadAlias("IdUuidPair", IdUuidPair.class);
     confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class);
     confBuilder.loadAlias("UuidWithProjectUuid", UuidWithProjectUuidDto.class);
     confBuilder.loadAlias("Event", EventDto.class);
@@ -230,7 +231,7 @@ public class MyBatis {
       GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
       MeasureMapper.class, MetricMapper.class, CustomMeasureMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class,
       ProjectQgateAssociationMapper.class, EventMapper.class,
-      AnalysisReportMapper.class, ComponentLinkMapper.class,
+      CeQueueMapper.class, CeActivityMapper.class, ComponentLinkMapper.class,
       Migration45Mapper.class, Migration50Mapper.class
     };
     confBuilder.loadMappers(mappers);
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java
new file mode 100644 (file)
index 0000000..59b59d6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Optional;
+import java.util.List;
+import org.apache.ibatis.session.RowBounds;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+public class CeActivityDao implements Dao {
+
+  private final System2 system2;
+
+  public CeActivityDao(System2 system2) {
+    this.system2 = system2;
+  }
+
+  public Optional<CeActivityDto> selectByUuid(DbSession dbSession, String uuid) {
+    return Optional.fromNullable(mapper(dbSession).selectByUuid(uuid));
+  }
+
+  public void insert(DbSession dbSession, CeActivityDto dto) {
+    dto.setCreatedAt(system2.now());
+    dto.setUpdatedAt(system2.now());
+    dto.setIsLast(false);
+    mapper(dbSession).insert(dto);
+
+    List<String> uuids = mapper(dbSession).selectUuidsOfRecentlyCreatedByIsLastKey(dto.getIsLastKey(), new RowBounds(0, 1));
+    // should never be empty, as a row was just inserted!
+    if (!uuids.isEmpty()) {
+      mapper(dbSession).updateIsLastToFalseForLastKey(dto.getIsLastKey(), dto.getUpdatedAt());
+      mapper(dbSession).updateIsLastToTrueForUuid(uuids.get(0), dto.getUpdatedAt());
+    }
+  }
+
+  /**
+   * Ordered by id asc -> oldest to newest
+   */
+  public List<CeActivityDto> selectByQuery(DbSession dbSession, CeActivityQuery query, RowBounds rowBounds) {
+    return mapper(dbSession).selectByQuery(query, rowBounds);
+  }
+
+  private CeActivityMapper mapper(DbSession dbSession) {
+    return dbSession.getMapper(CeActivityMapper.class);
+  }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java
new file mode 100644 (file)
index 0000000..db2f1a1
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
+
+public class CeActivityDto {
+
+  public enum Status {
+    SUCCESS, FAILED, CANCELED
+  }
+
+  private String uuid;
+  private String componentUuid;
+  private Status status;
+  private String taskType;
+  private boolean isLast;
+  private String isLastKey;
+  private String submitterLogin;
+  private long submittedAt;
+  private Long startedAt;
+  private Long finishedAt;
+  private long createdAt;
+  private long updatedAt;
+  private Long executionTimeMs;
+
+  CeActivityDto() {
+    // required for MyBatis
+  }
+
+  public CeActivityDto(CeQueueDto queueDto) {
+    this.uuid = queueDto.getUuid();
+    this.taskType = queueDto.getTaskType();
+    this.componentUuid = queueDto.getComponentUuid();
+    this.isLastKey = format("%s%s", taskType, Strings.nullToEmpty(componentUuid));
+    this.submitterLogin = queueDto.getSubmitterLogin();
+    this.submittedAt = queueDto.getCreatedAt();
+    this.startedAt = queueDto.getStartedAt();
+  }
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  public void setUuid(String s) {
+    checkArgument(s.length() <= 40, "Value is too long for column CE_ACTIVITY.UUID: %s", s);
+    this.uuid = s;
+  }
+
+  public String getTaskType() {
+    return taskType;
+  }
+
+  public void setTaskType(String s) {
+    this.taskType = s;
+  }
+
+  @CheckForNull
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  public void setComponentUuid(@Nullable String s) {
+    checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_ACTIVITY.COMPONENT_UUID: %s", s);
+    this.componentUuid = s;
+  }
+
+  public Status getStatus() {
+    return status;
+  }
+
+  public void setStatus(Status s) {
+    this.status = s;
+  }
+
+  public boolean getIsLast() {
+    return isLast;
+  }
+
+  void setIsLast(boolean b) {
+    this.isLast = b;
+  }
+
+  public String getIsLastKey() {
+    return isLastKey;
+  }
+
+  @CheckForNull
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  public long getSubmittedAt() {
+    return submittedAt;
+  }
+
+  public void setSubmittedAt(long submittedAt) {
+    this.submittedAt = submittedAt;
+  }
+
+  @CheckForNull
+  public Long getStartedAt() {
+    return startedAt;
+  }
+
+  public void setStartedAt(@Nullable Long l) {
+    this.startedAt = l;
+  }
+
+  @CheckForNull
+  public Long getFinishedAt() {
+    return finishedAt;
+  }
+
+  public void setFinishedAt(@Nullable Long l) {
+    this.finishedAt = l;
+  }
+
+  public long getCreatedAt() {
+    return createdAt;
+  }
+
+  public void setCreatedAt(long l) {
+    this.createdAt = l;
+  }
+
+  public long getUpdatedAt() {
+    return updatedAt;
+  }
+
+  public void setUpdatedAt(long l) {
+    this.updatedAt = l;
+  }
+
+  @CheckForNull
+  public Long getExecutionTimeMs() {
+    return executionTimeMs;
+  }
+
+  public void setExecutionTimeMs(@Nullable Long l) {
+    checkArgument(l == null || l >= 0, "Execution time must be positive: %s", l);
+    this.executionTimeMs = l;
+  }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("uuid", uuid)
+      .add("taskType", taskType)
+      .add("componentUuid", componentUuid)
+      .add("status", status)
+      .add("isLast", isLast)
+      .add("isLastKey", isLastKey)
+      .add("submitterLogin", submitterLogin)
+      .add("submittedAt", submittedAt)
+      .add("startedAt", startedAt)
+      .add("finishedAt", finishedAt)
+      .add("createdAt", createdAt)
+      .add("updatedAt", updatedAt)
+      .add("executionTimeMs", executionTimeMs)
+      .toString();
+  }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java
new file mode 100644 (file)
index 0000000..2660946
--- /dev/null
@@ -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.db.ce;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.session.RowBounds;
+
+public interface CeActivityMapper {
+
+  List<String> selectUuidsOfRecentlyCreatedByIsLastKey(@Param("isLastKey") String isLastKey, RowBounds rowBounds);
+
+  @CheckForNull
+  CeActivityDto selectByUuid(@Param("uuid") String uuid);
+
+  List<CeActivityDto> selectByComponentUuid(@Param("componentUuid") String componentUuid);
+
+  List<CeActivityDto> selectByQuery(@Param("query") CeActivityQuery query, RowBounds rowBounds);
+
+  void insert(CeActivityDto dto);
+
+  void updateIsLastToFalseForLastKey(@Param("isLastKey") String isLastKey, @Param("updatedAt") long updatedAt);
+
+  void updateIsLastToTrueForUuid(@Param("uuid") String uuid, @Param("updatedAt") long updatedAt);
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityQuery.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityQuery.java
new file mode 100644 (file)
index 0000000..f0e57fd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.db.ce;
+
+public class CeActivityQuery {
+
+  private boolean onlyCurrents = false;
+  private String componentUuid;
+  private CeActivityDto.Status status;
+  private String type;
+
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  public CeActivityQuery setComponentUuid(String componentUuid) {
+    this.componentUuid = componentUuid;
+    return this;
+  }
+
+  public boolean isOnlyCurrents() {
+    return onlyCurrents;
+  }
+
+  public CeActivityQuery setOnlyCurrents(boolean onlyCurrents) {
+    this.onlyCurrents = onlyCurrents;
+    return this;
+  }
+
+  public CeActivityDto.Status getStatus() {
+    return status;
+  }
+
+  public CeActivityQuery setStatus(CeActivityDto.Status status) {
+    this.status = status;
+    return this;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public CeActivityQuery setType(String type) {
+    this.type = type;
+    return this;
+  }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java
new file mode 100644 (file)
index 0000000..dc78ae8
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Optional;
+import java.util.List;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+import static org.sonar.db.ce.CeQueueDto.Status.PENDING;
+import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS;
+
+public class CeQueueDao implements Dao {
+
+  private final System2 system2;
+
+  public CeQueueDao(System2 system2) {
+    this.system2 = system2;
+  }
+
+  /**
+   * Ordered by ascending id: oldest to newest
+   */
+  public List<CeQueueDto> selectAllInAscOrder(DbSession session) {
+    return mapper(session).selectAllInAscOrder();
+  }
+
+  /**
+   * Ordered by ascending id: oldest to newest
+   */
+  public List<CeQueueDto> selectByComponentUuid(DbSession session, String componentUuid) {
+    return mapper(session).selectByComponentUuid(componentUuid);
+  }
+
+  public Optional<CeQueueDto> selectByUuid(DbSession session, String uuid) {
+    return Optional.fromNullable(mapper(session).selectByUuid(uuid));
+  }
+
+  public CeQueueDto insert(DbSession session, CeQueueDto dto) {
+    dto.setCreatedAt(system2.now());
+    dto.setUpdatedAt(system2.now());
+    mapper(session).insert(dto);
+    return dto;
+  }
+
+  public void deleteByUuid(DbSession session, String uuid) {
+    mapper(session).deleteByUuid(uuid);
+  }
+
+  /**
+   * Update all rows with: STATUS='PENDING', STARTED_AT=NULL, UPDATED_AT={now}
+   */
+  public void resetAllToPendingStatus(DbSession session) {
+    mapper(session).resetAllToPendingStatus(system2.now());
+  }
+
+  public int countByStatus(DbSession dbSession, CeQueueDto.Status status) {
+    return mapper(dbSession).countByStatus(status);
+  }
+
+  public int countAll(DbSession dbSession) {
+    return mapper(dbSession).countAll();
+  }
+
+  public Optional<CeQueueDto> peek(DbSession session) {
+    List<String> taskUuids = mapper(session).selectEligibleForPeek();
+    if (taskUuids.isEmpty()) {
+      return Optional.absent();
+    }
+
+    String taskUuid = taskUuids.get(0);
+    return tryToPeek(session, taskUuid);
+  }
+
+  private Optional<CeQueueDto> tryToPeek(DbSession session, String taskUuid) {
+    int touchedRows = mapper(session).updateIfStatus(taskUuid, IN_PROGRESS, system2.now(), system2.now(), PENDING);
+    if (touchedRows != 1) {
+      session.rollback();
+      return Optional.absent();
+    }
+
+    CeQueueDto result = mapper(session).selectByUuid(taskUuid);
+    session.commit();
+    return Optional.of(result);
+  }
+
+  private CeQueueMapper mapper(DbSession session) {
+    return session.getMapper(CeQueueMapper.class);
+  }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java
new file mode 100644 (file)
index 0000000..559fa6f
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class CeQueueDto {
+
+  public enum Status {
+    PENDING, IN_PROGRESS
+  }
+
+  private String uuid;
+  private String taskType;
+  private String componentUuid;
+  private Status status;
+  private String submitterLogin;
+  private Long startedAt;
+  private long createdAt;
+  private long updatedAt;
+
+  public String getUuid() {
+    return uuid;
+  }
+
+  public void setUuid(String s) {
+    checkArgument(s.length() <= 40, "Value is too long for column CE_QUEUE.UUID: %s", s);
+    this.uuid = s;
+  }
+
+  @CheckForNull
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  public void setComponentUuid(@Nullable String s) {
+    checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_QUEUE.COMPONENT_UUID: %s", s);
+    this.componentUuid = s;
+  }
+
+  public Status getStatus() {
+    return status;
+  }
+
+  public void setStatus(Status s) {
+    this.status = s;
+  }
+
+  public String getTaskType() {
+    return taskType;
+  }
+
+  public void setTaskType(String s) {
+    checkArgument(s.length() <= 15, "Value is too long for column CE_QUEUE.TASK_TYPE: %s", s);
+    this.taskType = s;
+  }
+
+  @CheckForNull
+  public String getSubmitterLogin() {
+    return submitterLogin;
+  }
+
+  public void setSubmitterLogin(@Nullable String s) {
+    checkArgument(s == null || s.length() <= 255, "Value is too long for column CE_QUEUE.SUBMITTER_LOGIN: %s", s);
+    this.submitterLogin = s;
+  }
+
+  @CheckForNull
+  public Long getStartedAt() {
+    return startedAt;
+  }
+
+  public void setStartedAt(@Nullable Long l) {
+    this.startedAt = l;
+  }
+
+  public long getCreatedAt() {
+    return createdAt;
+  }
+
+  public void setCreatedAt(long l) {
+    this.createdAt = l;
+  }
+
+  public long getUpdatedAt() {
+    return updatedAt;
+  }
+
+  public void setUpdatedAt(long l) {
+    this.updatedAt = l;
+  }
+
+  @Override
+  public String toString() {
+    return Objects.toStringHelper(this)
+      .add("uuid", uuid)
+      .add("taskType", taskType)
+      .add("componentUuid", componentUuid)
+      .add("status", status)
+      .add("submitterLogin", submitterLogin)
+      .add("startedAt", startedAt)
+      .add("createdAt", createdAt)
+      .add("updatedAt", updatedAt)
+      .toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CeQueueDto that = (CeQueueDto) o;
+    return uuid.equals(that.uuid);
+
+  }
+
+  @Override
+  public int hashCode() {
+    return uuid.hashCode();
+  }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java
new file mode 100644 (file)
index 0000000..18c8d1d
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.db.ce;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.ibatis.annotations.Param;
+
+public interface CeQueueMapper {
+
+  List<CeQueueDto> selectByComponentUuid(@Param("componentUuid") String componentUuid);
+
+  List<CeQueueDto> selectAllInAscOrder();
+
+  List<String> selectEligibleForPeek();
+
+  @CheckForNull
+  CeQueueDto selectByUuid(@Param("uuid") String uuid);
+
+  int countByStatus(@Param("status") CeQueueDto.Status status);
+
+  int countAll();
+
+  void insert(CeQueueDto dto);
+
+  void resetAllToPendingStatus(@Param("updatedAt") long updatedAt);
+
+  int updateIfStatus(@Param("uuid") String uuid,
+    @Param("newStatus") CeQueueDto.Status newStatus,
+    @Nullable @Param("startedAt") Long startedAt,
+    @Param("updatedAt") long updatedAt,
+    @Param("oldStatus") CeQueueDto.Status oldStatus);
+
+  void deleteByUuid(@Param("uuid") String uuid);
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeTaskTypes.java b/sonar-db/src/main/java/org/sonar/db/ce/CeTaskTypes.java
new file mode 100644 (file)
index 0000000..042ff5e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.db.ce;
+
+public class CeTaskTypes {
+
+  private CeTaskTypes() {
+    // only statics
+  }
+
+  public static final String REPORT = "REPORT";
+
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/package-info.java b/sonar-db/src/main/java/org/sonar/db/ce/package-info.java
new file mode 100644 (file)
index 0000000..0b22b70
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.db.ce;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDao.java b/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDao.java
deleted file mode 100644 (file)
index 10d6df6..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.db.compute;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.sonar.api.utils.System2;
-import org.sonar.db.Dao;
-import org.sonar.db.DbSession;
-
-import static org.sonar.db.compute.AnalysisReportDto.Status.PENDING;
-import static org.sonar.db.compute.AnalysisReportDto.Status.WORKING;
-
-public class AnalysisReportDao implements Dao {
-
-  private System2 system2;
-
-  public AnalysisReportDao(System2 system2) {
-    this.system2 = system2;
-  }
-
-  /**
-   * Update all rows with: STATUS='PENDING', STARTED_AT=NULL, UPDATED_AT={now}
-   */
-  public void resetAllToPendingStatus(DbSession session) {
-    mapper(session).resetAllToPendingStatus(system2.now());
-  }
-
-  public void truncate(DbSession session) {
-    mapper(session).truncate();
-  }
-
-  public List<AnalysisReportDto> selectByProjectKey(DbSession session, String projectKey) {
-    return mapper(session).selectByProjectKey(projectKey);
-  }
-
-  @VisibleForTesting
-  AnalysisReportDto selectById(DbSession session, long id) {
-    return mapper(session).selectById(id);
-  }
-
-  @CheckForNull
-  public AnalysisReportDto pop(DbSession session) {
-    List<Long> reportIds = mapper(session).selectAvailables(PENDING, WORKING);
-    if (reportIds.isEmpty()) {
-      return null;
-    }
-
-    long reportId = reportIds.get(0);
-    return tryToPop(session, reportId);
-  }
-
-  public long countPending(DbSession session) {
-    return mapper(session).selectAvailables(PENDING, WORKING).size();
-  }
-
-  @VisibleForTesting
-  AnalysisReportDto tryToPop(DbSession session, long reportId) {
-    AnalysisReportMapper mapper = mapper(session);
-    int nbOfReportBooked = mapper.updateWithBookingReport(reportId, system2.now(), PENDING, WORKING);
-    if (nbOfReportBooked == 0) {
-      return null;
-    }
-
-    AnalysisReportDto result = mapper.selectById(reportId);
-    session.commit();
-    return result;
-  }
-
-  public List<AnalysisReportDto> selectAll(DbSession session) {
-    return mapper(session).selectAll();
-  }
-
-  public AnalysisReportDto insert(DbSession session, AnalysisReportDto report) {
-    report.setCreatedAt(system2.now());
-    report.setUpdatedAt(system2.now());
-    mapper(session).insert(report);
-    return report;
-  }
-
-  public void delete(DbSession session, long id) {
-    mapper(session).delete(id);
-  }
-
-  private AnalysisReportMapper mapper(DbSession session) {
-    return session.getMapper(AnalysisReportMapper.class);
-  }
-}
diff --git a/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDto.java b/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportDto.java
deleted file mode 100644 (file)
index 010afe1..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.db.compute;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import javax.annotation.CheckForNull;
-
-public class AnalysisReportDto {
-  private Long id;
-  private String projectKey;
-  private String projectName;
-  private Status status;
-  private String uuid;
-  private Long createdAt;
-  private Long updatedAt;
-  private Long startedAt;
-  private Long finishedAt;
-
-  @VisibleForTesting
-  public static AnalysisReportDto newForTests(Long id) {
-    AnalysisReportDto report = new AnalysisReportDto();
-    report.id = id;
-
-    return report;
-  }
-
-  public String getProjectKey() {
-    return projectKey;
-  }
-
-  public AnalysisReportDto setProjectKey(String projectKey) {
-    this.projectKey = projectKey;
-    return this;
-  }
-
-  public String getProjectName() {
-    return projectName;
-  }
-
-  public AnalysisReportDto setProjectName(String projectName) {
-    this.projectName = projectName;
-    return this;
-  }
-
-  public Status getStatus() {
-    return status;
-  }
-
-  public AnalysisReportDto setStatus(Status status) {
-    this.status = status;
-    return this;
-  }
-
-  public String getUuid() {
-    return uuid;
-  }
-
-  public AnalysisReportDto setUuid(String s) {
-    this.uuid = s;
-    return this;
-  }
-
-  public Long getId() {
-    return id;
-  }
-
-  public void setId(Long id) {
-    this.id = id;
-  }
-
-  @Override
-  public String toString() {
-    return Objects.toStringHelper(this)
-      .add("id", getId())
-      .add("projectKey", getProjectKey())
-      .add("uuid", getUuid())
-      .add("status", getStatus())
-      .add("createdAt", getCreatedAt())
-      .add("startedAt", getStartedAt())
-      .add("finishedAt", getFinishedAt())
-      .toString();
-  }
-
-  @CheckForNull
-  public Long getStartedAt() {
-    return startedAt;
-  }
-
-  public AnalysisReportDto setStartedAt(Long startedAt) {
-    this.startedAt = startedAt;
-    return this;
-  }
-
-  @CheckForNull
-  public Long getFinishedAt() {
-    return finishedAt;
-  }
-
-  public AnalysisReportDto setFinishedAt(Long finishedAt) {
-    this.finishedAt = finishedAt;
-    return this;
-  }
-
-  public Long getCreatedAt() {
-    return createdAt;
-  }
-
-  public AnalysisReportDto setCreatedAt(Long createdAt) {
-    this.createdAt = createdAt;
-    return this;
-  }
-
-  public Long getUpdatedAt() {
-    return updatedAt;
-  }
-
-  public AnalysisReportDto setUpdatedAt(Long updatedAt) {
-    this.updatedAt = updatedAt;
-    return this;
-  }
-
-  public enum Status {
-    PENDING, WORKING, SUCCESS, FAILED, CANCELLED
-  }
-}
diff --git a/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportMapper.java b/sonar-db/src/main/java/org/sonar/db/compute/AnalysisReportMapper.java
deleted file mode 100644 (file)
index daa9e46..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.db.compute;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-
-public interface AnalysisReportMapper {
-  List<AnalysisReportDto> selectByProjectKey(String projectKey);
-
-  List<Long> selectAvailables(
-    @Param("availableStatus") AnalysisReportDto.Status availableStatus,
-    @Param("busyStatus") AnalysisReportDto.Status busyStatus);
-
-  void resetAllToPendingStatus(@Param("updatedAt") long updatedAt);
-
-  void truncate();
-
-  void insert(AnalysisReportDto reportDto);
-
-  int update(AnalysisReportDto report);
-
-  int updateWithBookingReport(@Param("id") Long id, @Param("startedAt") long startedAt,
-    @Param("availableStatus") AnalysisReportDto.Status availableStatus,
-    @Param("busyStatus") AnalysisReportDto.Status busyStatus);
-
-  AnalysisReportDto selectById(long id);
-
-  void delete(long id);
-
-  List<AnalysisReportDto> selectAll();
-}
diff --git a/sonar-db/src/main/java/org/sonar/db/compute/package-info.java b/sonar-db/src/main/java/org/sonar/db/compute/package-info.java
deleted file mode 100644 (file)
index 240f322..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.db.compute;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
index c8a0ded3816c30c36a7dc74456061d71e81a3c06..3e00526a1f0a70c6c244f36ac73006ec539ea413 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.db.MyBatis;
 
 public class DatabaseVersion {
 
-  public static final int LAST_VERSION = 931;
+  public static final int LAST_VERSION = 934;
 
   /**
    * The minimum supported version which can be upgraded. Lower
@@ -49,8 +49,9 @@ public class DatabaseVersion {
     "active_rules",
     "active_rule_parameters",
     "activities",
-    "analysis_reports",
     "authors",
+    "ce_activity",
+    "ce_queue",
     "characteristics",
     "dashboards",
     "duplications_index",
index 9f60c1336603b6f2aef03adb498bb61672058975..30179824198146ec6f8232e564ac654caef9e58a 100644 (file)
@@ -47,6 +47,7 @@ import org.sonar.db.version.v51.RemovePermissionsOnModulesMigrationStep;
 import org.sonar.db.version.v51.RenameComponentRelatedParamsInIssueFilters;
 import org.sonar.db.version.v51.UpdateProjectsModuleUuidPath;
 import org.sonar.db.version.v52.AddManualMeasuresComponentUuidColumn;
+import org.sonar.db.version.v52.RemoveAnalysisReportsFromActivities;
 import org.sonar.db.version.v52.FeedEventsComponentUuid;
 import org.sonar.db.version.v52.FeedFileSourcesDataType;
 import org.sonar.db.version.v52.FeedManualMeasuresComponentUuid;
@@ -105,6 +106,7 @@ public class MigrationStepModule extends Module {
       RemoveSnapshotLibraries.class,
       RemoveComponentLibraries.class,
       RemoveDuplicatedComponentKeys.class,
-      IncreasePrecisionOfNumerics.class);
+      IncreasePrecisionOfNumerics.class,
+      RemoveAnalysisReportsFromActivities.class);
   }
 }
diff --git a/sonar-db/src/main/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivities.java b/sonar-db/src/main/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivities.java
new file mode 100644 (file)
index 0000000..74cfd44
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.db.version.v52;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.version.BaseDataChange;
+import org.sonar.db.version.MassUpdate;
+import org.sonar.db.version.Select;
+import org.sonar.db.version.SqlStatement;
+
+/**
+ * Items moved to table CE_ACTIVITY
+ * @since 5.2
+ */
+public class RemoveAnalysisReportsFromActivities extends BaseDataChange {
+
+  public RemoveAnalysisReportsFromActivities(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate.select("select id from activities where log_type='ANALYSIS_REPORT'");
+    massUpdate.update("delete from activities where id=?");
+    massUpdate.execute(new MassUpdate.Handler() {
+      @Override
+      public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+        update.setLong(1, row.getLong(1));
+        return true;
+      }
+    });
+  }
+}
diff --git a/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml b/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml
new file mode 100644 (file)
index 0000000..fcd588a
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.ce.CeActivityMapper">
+
+  <sql id="columns">
+    ca.uuid,
+    ca.task_type as taskType,
+    ca.component_uuid as componentUuid,
+    ca.status as status,
+    ca.submitter_login as submitterLogin,
+    ca.submitted_at as submittedAt,
+    ca.started_at as startedAt,
+    ca.finished_at as finishedAt,
+    ca.created_at as createdAt,
+    ca.updated_at as updatedAt,
+    ca.is_last as isLast,
+    ca.is_last_key as isLastKey,
+    ca.execution_time_ms as executionTimeMs
+  </sql>
+
+  <select id="selectByUuid" parameterType="String" resultType="org.sonar.db.ce.CeActivityDto">
+    select
+    <include refid="columns"/>
+    from ce_activity ca
+    where ca.uuid=#{uuid}
+  </select>
+
+  <select id="selectByComponentUuid" parameterType="String" resultType="org.sonar.db.ce.CeActivityDto">
+    select
+    <include refid="columns"/>
+    from ce_activity ca
+    where ca.component_uuid=#{componentUuid}
+    order by ca.id asc
+  </select>
+
+  <select id="selectUuidsOfRecentlyCreatedByIsLastKey" parameterType="String" resultType="String">
+    select uuid
+    from ce_activity
+    where is_last_key=#{isLastKey}
+    order by id desc
+  </select>
+
+  <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.ce.CeActivityDto">
+    select
+    <include refid="columns"/>
+    from ce_activity ca
+    <where>
+      <if test="query.onlyCurrents">
+        ca.is_last=${_true}
+      </if>
+      <if test="query.componentUuid != null">
+        ca.component_uuid=#{query.componentUuid}
+      </if>
+      <if test="query.status != null">
+        ca.status=#{query.status}
+      </if>
+      <if test="query.type != null">
+        ca.task_type=#{query.type}
+      </if>
+    </where>
+    order by ca.id desc
+  </select>
+
+  <insert id="insert" parameterType="org.sonar.db.ce.CeActivityDto" useGeneratedKeys="false">
+    insert into ce_activity
+    (uuid, component_uuid, status, task_type, is_last, is_last_key, submitter_login, submitted_at, started_at,
+    finished_at, created_at, updated_at, execution_time_ms)
+    values (
+    #{uuid,jdbcType=VARCHAR},
+    #{componentUuid,jdbcType=VARCHAR},
+    #{status,jdbcType=VARCHAR},
+    #{taskType,jdbcType=VARCHAR},
+    #{isLast,jdbcType=BOOLEAN},
+    #{isLastKey,jdbcType=VARCHAR},
+    #{submitterLogin,jdbcType=VARCHAR},
+    #{submittedAt,jdbcType=BIGINT},
+    #{startedAt,jdbcType=BIGINT},
+    #{finishedAt,jdbcType=BIGINT},
+    #{createdAt,jdbcType=BIGINT},
+    #{updatedAt,jdbcType=BIGINT},
+    #{executionTimeMs,jdbcType=BIGINT}
+    )
+  </insert>
+
+  <update id="updateIsLastToFalseForLastKey" parameterType="map">
+    update ce_activity
+    set is_last=${_false},
+    updated_at=#{updatedAt,jdbcType=BIGINT}
+    where is_last=${_true} and is_last_key=#{isLastKey}
+  </update>
+
+  <update id="updateIsLastToTrueForUuid" parameterType="map">
+    update ce_activity
+    set is_last=${_true},
+    updated_at=#{updatedAt,jdbcType=BIGINT}
+    where uuid=#{uuid}
+  </update>
+
+</mapper>
diff --git a/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml b/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml
new file mode 100644 (file)
index 0000000..42b26d3
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.ce.CeQueueMapper">
+
+  <sql id="columns">
+    cq.uuid,
+    cq.task_type as taskType,
+    cq.component_uuid as componentUuid,
+    cq.status as status,
+    cq.submitter_login as submitterLogin,
+    cq.started_at as startedAt,
+    cq.created_at as createdAt,
+    cq.updated_at as updatedAt
+  </sql>
+
+  <select id="selectByUuid" parameterType="String" resultType="org.sonar.db.ce.CeQueueDto">
+    select
+    <include refid="columns"/>
+    from ce_queue cq
+    where cq.uuid=#{uuid}
+  </select>
+
+  <select id="countByStatus" parameterType="org.sonar.db.ce.CeQueueDto$Status" resultType="int">
+    select count(id) from ce_queue where status=#{status}
+  </select>
+
+  <select id="countAll" resultType="int">
+    select count(id) from ce_queue
+  </select>
+
+  <select id="selectByComponentUuid" parameterType="String" resultType="org.sonar.db.ce.CeQueueDto">
+    select
+    <include refid="columns"/>
+    from ce_queue cq
+    where cq.component_uuid=#{componentUuid}
+    order by cq.id asc
+  </select>
+
+  <select id="selectAllInAscOrder" resultType="org.sonar.db.ce.CeQueueDto">
+    select
+    <include refid="columns"/>
+    from ce_queue cq
+    order by cq.id asc
+  </select>
+
+  <select id="selectEligibleForPeek" resultType="String">
+    select cq.uuid
+    from ce_queue cq
+    where cq.status='PENDING'
+    and not exists(
+    select 1
+    from ce_queue cq2
+    where cq.component_uuid=cq2.component_uuid and cq2.status &lt;&gt; 'PENDING'
+    )
+    order by cq.created_at asc, cq.id asc
+  </select>
+
+  <insert id="insert" parameterType="org.sonar.db.ce.CeQueueDto" useGeneratedKeys="false">
+    insert into ce_queue
+    (uuid, task_type, component_uuid, status, submitter_login, started_at, created_at, updated_at)
+    values (
+    #{uuid,jdbcType=VARCHAR},
+    #{taskType,jdbcType=VARCHAR},
+    #{componentUuid,jdbcType=VARCHAR},
+    #{status,jdbcType=VARCHAR},
+    #{submitterLogin,jdbcType=VARCHAR},
+    #{startedAt,jdbcType=BIGINT},
+    #{createdAt,jdbcType=BIGINT},
+    #{updatedAt,jdbcType=BIGINT}
+    )
+  </insert>
+
+  <update id="resetAllToPendingStatus" parameterType="map">
+    update ce_queue
+    set status='PENDING', started_at=NULL, updated_at=#{updatedAt,jdbcType=BIGINT}
+    where status &lt;&gt; 'PENDING'
+  </update>
+
+  <update id="updateIfStatus" parameterType="map">
+    update ce_queue
+    set status=#{newStatus,jdbcType=VARCHAR},
+    started_at=#{startedAt,jdbcType=BIGINT},
+    updated_at=#{updatedAt,jdbcType=BIGINT}
+    where uuid=#{uuid} and status=#{oldStatus}
+  </update>
+
+  <delete id="deleteByUuid">
+    delete from ce_queue where uuid=#{uuid}
+  </delete>
+
+</mapper>
diff --git a/sonar-db/src/main/resources/org/sonar/db/compute/AnalysisReportMapper.xml b/sonar-db/src/main/resources/org/sonar/db/compute/AnalysisReportMapper.xml
deleted file mode 100644 (file)
index 2a37001..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
-<mapper namespace="org.sonar.db.compute.AnalysisReportMapper">
-  <sql id="reportColumns">
-    <!-- the data report is not brought back by default as it could be too big in memory -->
-    ar.id,
-    ar.project_key as projectKey,
-    ar.project_name as projectName,
-    ar.report_status as status,
-    ar.uuid as uuid,
-    ar.created_at as createdAt,
-    ar.updated_at as updatedAt,
-    ar.started_at as startedAt,
-    ar.finished_at as finishedAt
-  </sql>
-
-  <insert id="insert" parameterType="AnalysisReport" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
-    insert into analysis_reports
-    (project_key, project_name, uuid, report_status, created_at, updated_at, started_at, finished_at)
-    values (
-    #{projectKey,jdbcType=VARCHAR}, #{projectName,jdbcType=VARCHAR}, #{uuid,jdbcType=VARCHAR},
-    #{status,jdbcType=VARCHAR},
-    #{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT}, #{startedAt,jdbcType=BIGINT},
-    #{finishedAt,jdbcType=BIGINT}
-    )
-  </insert>
-
-  <update id="resetAllToPendingStatus" parameterType="map">
-    update analysis_reports
-    set report_status='PENDING', updated_at=#{updatedAt,jdbcType=BIGINT}, started_at=NULL
-  </update>
-
-  <update id="updateWithBookingReport" parameterType="map">
-    update analysis_reports
-    set report_status=#{busyStatus,jdbcType=VARCHAR},
-    started_at=#{startedAt,jdbcType=BIGINT}
-    where id=#{id} and report_status=#{availableStatus}
-  </update>
-
-  <delete id="truncate">
-    truncate table analysis_reports
-  </delete>
-
-  <delete id="delete">
-    delete from analysis_reports where id=#{id}
-  </delete>
-
-  <select id="selectById" resultType="AnalysisReport">
-    select
-    <include refid="reportColumns"/>
-    from analysis_reports ar
-    where id = #{id}
-  </select>
-
-  <select id="selectByProjectKey" parameterType="String" resultType="AnalysisReport">
-    select
-    <include refid="reportColumns"/>
-    from analysis_reports ar
-    where project_key = #{projectKey}
-  </select>
-
-  <!-- TODO optimize by restricting results to first row (LIMIT 1 on most dbs) -->
-  <select id="selectAvailables" parameterType="map" resultType="Long">
-    select ar.id
-    from analysis_reports ar
-    where ar.report_status=#{availableStatus}
-    and not exists(
-    select 1
-    from analysis_reports ar2
-    where ar.project_key = ar2.project_key
-    and ar2.report_status=#{busyStatus}
-    )
-    order by ar.created_at asc, ar.id asc
-  </select>
-
-  <select id="selectAll" resultType="AnalysisReport">
-    select
-    <include refid="reportColumns"/>
-    from analysis_reports ar
-  </select>
-</mapper>
index d8b4310588dafbc2929ee22c395df512fffce36a..a2d75b28898d89057d7f852a1120c7117185e89d 100644 (file)
@@ -9,8 +9,9 @@ INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (2, 1, null, 'pr
 INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (3, 1, null, 'shareDashboard');
 INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (4, null, null, 'scan');
 INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (5, null, null, 'dryRunScan');
-INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (6, 1, null, 'provisioning');
-ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 7;
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (6, null, null, 'provisioning');
+INSERT INTO GROUP_ROLES(ID, GROUP_ID, RESOURCE_ID, ROLE) VALUES (7, 1, null, 'provisioning');
+ALTER TABLE GROUP_ROLES ALTER COLUMN ID RESTART WITH 8;
 
 INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 1);
 INSERT INTO GROUPS_USERS(USER_ID, GROUP_ID) VALUES (1, 2);
@@ -349,6 +350,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('927');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('929');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('930');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('931');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('932');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('933');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('934');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
index a1a27b835e6d920bf9aed74d416b76912c36ff7b..92e95d0cc2b201437e2b64e8a57242822aca1a45 100644 (file)
@@ -534,6 +534,35 @@ CREATE TABLE "FILE_SOURCES" (
   "UPDATED_AT" BIGINT NOT NULL
 );
 
+CREATE TABLE "CE_QUEUE" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "UUID" VARCHAR(40) NOT NULL,
+  "TASK_TYPE" VARCHAR(15) NOT NULL,
+  "COMPONENT_UUID" VARCHAR(40) NULL,
+  "STATUS" VARCHAR(15) NOT NULL,
+  "SUBMITTER_LOGIN" VARCHAR(255) NULL,
+  "STARTED_AT" BIGINT NULL,
+  "CREATED_AT" BIGINT NOT NULL,
+  "UPDATED_AT" BIGINT NOT NULL
+);
+
+CREATE TABLE "CE_ACTIVITY" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "UUID" VARCHAR(40) NOT NULL,
+  "TASK_TYPE" VARCHAR(15) NOT NULL,
+  "COMPONENT_UUID" VARCHAR(40) NULL,
+  "STATUS" VARCHAR(15) NOT NULL,
+  "IS_LAST" BOOLEAN NOT NULL,
+  "IS_LAST_KEY" VARCHAR(55) NOT NULL,
+  "SUBMITTER_LOGIN" VARCHAR(255) NULL,
+  "SUBMITTED_AT" BIGINT NOT NULL,
+  "STARTED_AT" BIGINT NULL,
+  "FINISHED_AT" BIGINT NULL,
+  "CREATED_AT" BIGINT NOT NULL,
+  "UPDATED_AT" BIGINT NOT NULL,
+  "EXECUTION_TIME_MS" BIGINT NULL
+);
+
 -- ----------------------------------------------
 -- DDL Statements for indexes
 -- ----------------------------------------------
@@ -675,3 +704,7 @@ CREATE UNIQUE INDEX "FILE_SOURCES_UUID_TYPE_UNIQUE" ON "FILE_SOURCES" ("FILE_UUI
 CREATE INDEX "FILE_SOURCES_UPDATED_AT" ON "FILE_SOURCES" ("UPDATED_AT");
 
 CREATE UNIQUE INDEX "PROJECT_QPROFILES_UNIQUE" ON "PROJECT_QPROFILES" ("PROJECT_UUID", "PROFILE_KEY");
+
+CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID");
+
+CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID");
index eb4d016d162d7090c9601864b4779d7b0e93b0da..29e06e13da5ec14c2b5384bb8d81f867b3580ab9 100644 (file)
@@ -30,6 +30,6 @@ public class DaoModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new DaoModule().configure(container);
-    assertThat(container.size()).isEqualTo(46);
+    assertThat(container.size()).isEqualTo(47);
   }
 }
diff --git a/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java b/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java
new file mode 100644 (file)
index 0000000..25d167a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Optional;
+import java.util.List;
+import org.apache.ibatis.session.RowBounds;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.DbTester;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.ce.CeTaskTypes.REPORT;
+
+@Category(DbTests.class)
+public class CeActivityDaoTest {
+
+  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
+
+  @Rule
+  public DbTester db = DbTester.create(system2);
+
+  CeActivityDao underTest = new CeActivityDao(system2);
+
+  @Test
+  public void test_insert() {
+    insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
+
+    Optional<CeActivityDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1");
+    assertThat(saved.isPresent()).isTrue();
+    assertThat(saved.get().getUuid()).isEqualTo("TASK_1");
+    assertThat(saved.get().getComponentUuid()).isEqualTo("PROJECT_1");
+    assertThat(saved.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
+    assertThat(saved.get().getSubmitterLogin()).isEqualTo("henri");
+    assertThat(saved.get().getIsLast()).isTrue();
+    assertThat(saved.get().getIsLastKey()).isEqualTo("REPORTPROJECT_1");
+    assertThat(saved.get().getSubmittedAt()).isEqualTo(1_300_000_000_000L);
+    assertThat(saved.get().getCreatedAt()).isEqualTo(1_450_000_000_000L);
+    assertThat(saved.get().getStartedAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(saved.get().getFinishedAt()).isEqualTo(1_500_000_000_500L);
+    assertThat(saved.get().getExecutionTimeMs()).isEqualTo(500L);
+  }
+
+  @Test
+  public void insert_must_set_relevant_is_last_field() {
+    // only a single task on PROJECT_1 -> is_last=true
+    insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isTrue();
+
+    // only a single task on PROJECT_2 -> is_last=true
+    insert("TASK_2", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS);
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();
+
+    // two tasks on PROJECT_1, the more recent one is TASK_3
+    insert("TASK_3", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isFalse();
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue();
+  }
+
+  @Test
+  public void test_selectByQuery() throws Exception {
+    insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
+    insert("TASK_2", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
+    insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS);
+    insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
+
+    // no filters
+    CeActivityQuery query = new CeActivityQuery();
+    List<CeActivityDto> dtos = underTest.selectByQuery(db.getSession(), query, new RowBounds(0, 10));
+    assertThat(dtos).extracting("uuid").containsExactly("TASK_4", "TASK_3", "TASK_2", "TASK_1");
+
+    // select by component uuid
+    query = new CeActivityQuery().setComponentUuid("PROJECT_1");
+    dtos = underTest.selectByQuery(db.getSession(), query, new RowBounds(0, 10));
+    assertThat(dtos).extracting("uuid").containsExactly("TASK_2", "TASK_1");
+
+    // select by status
+    query = new CeActivityQuery().setStatus(CeActivityDto.Status.SUCCESS);
+    dtos = underTest.selectByQuery(db.getSession(), query, new RowBounds(0, 10));
+    assertThat(dtos).extracting("uuid").containsExactly("TASK_4", "TASK_3", "TASK_1");
+
+    // select by type
+    query = new CeActivityQuery().setType(REPORT);
+    dtos = underTest.selectByQuery(db.getSession(), query, new RowBounds(0, 10));
+    assertThat(dtos).extracting("uuid").containsExactly("TASK_3", "TASK_2", "TASK_1");
+    query = new CeActivityQuery().setType("views");
+    dtos = underTest.selectByQuery(db.getSession(), query, new RowBounds(0, 10));
+    assertThat(dtos).extracting("uuid").containsExactly("TASK_4");
+  }
+
+  private void insert(String uuid, String type, String componentUuid, CeActivityDto.Status status) {
+    CeQueueDto queueDto = new CeQueueDto();
+    queueDto.setUuid(uuid);
+    queueDto.setTaskType(type);
+    queueDto.setComponentUuid(componentUuid);
+    queueDto.setSubmitterLogin("henri");
+    queueDto.setCreatedAt(1_300_000_000_000L);
+
+    CeActivityDto dto = new CeActivityDto(queueDto);
+    dto.setStatus(status);
+    dto.setStartedAt(1_500_000_000_000L);
+    dto.setFinishedAt(1_500_000_000_500L);
+    dto.setExecutionTimeMs(500L);
+    underTest.insert(db.getSession(), dto);
+  }
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java b/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java
new file mode 100644 (file)
index 0000000..761c8bf
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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.db.ce;
+
+import com.google.common.base.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.DbTester;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class CeQueueDaoTest {
+
+  System2 system2 = new TestSystem2().setNow(1_450_000_000_000L);
+
+  @Rule
+  public DbTester db = DbTester.create(system2);
+
+  CeQueueDao underTest = new CeQueueDao(system2);
+
+  @Test
+  public void test_insert() {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    Optional<CeQueueDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1");
+    assertThat(saved.isPresent()).isTrue();
+  }
+
+  @Test
+  public void test_selectByUuid() {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_UNKNOWN").isPresent()).isFalse();
+    CeQueueDto saved = underTest.selectByUuid(db.getSession(), "TASK_1").get();
+    assertThat(saved.getUuid()).isEqualTo("TASK_1");
+    assertThat(saved.getTaskType()).isEqualTo(CeTaskTypes.REPORT);
+    assertThat(saved.getComponentUuid()).isEqualTo("PROJECT_1");
+    assertThat(saved.getStatus()).isEqualTo(CeQueueDto.Status.PENDING);
+    assertThat(saved.getSubmitterLogin()).isEqualTo("henri");
+    assertThat(saved.getCreatedAt()).isEqualTo(1_450_000_000_000L);
+    assertThat(saved.getUpdatedAt()).isEqualTo(1_450_000_000_000L);
+    assertThat(saved.getStartedAt()).isNull();
+  }
+
+  @Test
+  public void test_selectByComponentUuid() {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_2", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_3", "PROJECT_2", CeQueueDto.Status.PENDING);
+
+    assertThat(underTest.selectByComponentUuid(db.getSession(), "UNKNOWN")).isEmpty();
+    assertThat(underTest.selectByComponentUuid(db.getSession(), "PROJECT_1")).extracting("uuid").containsOnly("TASK_1", "TASK_2");
+    assertThat(underTest.selectByComponentUuid(db.getSession(), "PROJECT_2")).extracting("uuid").containsOnly("TASK_3");
+  }
+
+  @Test
+  public void test_selectAllInAscOrder() {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_2", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_3", "PROJECT_2", CeQueueDto.Status.PENDING);
+
+    assertThat(underTest.selectAllInAscOrder(db.getSession())).extracting("uuid").containsOnly("TASK_1", "TASK_2", "TASK_3");
+  }
+
+  @Test
+  public void test_delete() {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    underTest.deleteByUuid(db.getSession(), "UNKNOWN");
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").isPresent()).isTrue();
+
+    underTest.deleteByUuid(db.getSession(), "TASK_1");
+    assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").isPresent()).isFalse();
+  }
+
+  @Test
+  public void test_resetAllToPendingStatus() throws Exception {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_2", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+    insert("TASK_3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(1);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(2);
+
+    underTest.resetAllToPendingStatus(db.getSession());
+
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(3);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(0);
+  }
+
+  @Test
+  public void peek_none_if_no_pendings() throws Exception {
+    assertThat(underTest.peek(db.getSession()).isPresent()).isFalse();
+
+    // not pending, but in progress
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
+    assertThat(underTest.peek(db.getSession()).isPresent()).isFalse();
+  }
+
+  @Test
+  public void peek_oldest_pending() throws Exception {
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_2", "PROJECT_2", CeQueueDto.Status.PENDING);
+    assertThat(underTest.countAll(db.getSession())).isEqualTo(2);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(2);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(0);
+
+    // peek first one
+    Optional<CeQueueDto> peek = underTest.peek(db.getSession());
+    assertThat(peek.isPresent()).isTrue();
+    assertThat(peek.get().getUuid()).isEqualTo("TASK_1");
+    assertThat(peek.get().getStatus()).isEqualTo(CeQueueDto.Status.IN_PROGRESS);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(1);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(1);
+
+    // peek second one
+    peek = underTest.peek(db.getSession());
+    assertThat(peek.isPresent()).isTrue();
+    assertThat(peek.get().getUuid()).isEqualTo("TASK_2");
+    assertThat(peek.get().getStatus()).isEqualTo(CeQueueDto.Status.IN_PROGRESS);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(0);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(2);
+
+    // no more pendings
+    assertThat(underTest.peek(db.getSession()).isPresent()).isFalse();
+  }
+
+  @Test
+  public void do_not_peek_multiple_tasks_on_same_project_at_the_same_time() throws Exception {
+    // two pending tasks on the same project
+    insert("TASK_1", "PROJECT_1", CeQueueDto.Status.PENDING);
+    insert("TASK_2", "PROJECT_1", CeQueueDto.Status.PENDING);
+
+    Optional<CeQueueDto> peek = underTest.peek(db.getSession());
+    assertThat(peek.isPresent()).isTrue();
+    assertThat(peek.get().getUuid()).isEqualTo("TASK_1");
+    assertThat(underTest.countAll(db.getSession())).isEqualTo(2);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.PENDING)).isEqualTo(1);
+    assertThat(underTest.countByStatus(db.getSession(), CeQueueDto.Status.IN_PROGRESS)).isEqualTo(1);
+
+    // do not peek second task as long as the first one is in progress
+    peek = underTest.peek(db.getSession());
+    assertThat(peek.isPresent()).isFalse();
+
+    // first one is finished
+    underTest.deleteByUuid(db.getSession(), "TASK_1");
+    peek = underTest.peek(db.getSession());
+    assertThat(peek.get().getUuid()).isEqualTo("TASK_2");
+  }
+
+  private void insert(String uuid, String componentUuid, CeQueueDto.Status status) {
+    CeQueueDto dto = new CeQueueDto();
+    dto.setUuid(uuid);
+    dto.setTaskType(CeTaskTypes.REPORT);
+    dto.setComponentUuid(componentUuid);
+    dto.setStatus(status);
+    dto.setSubmitterLogin("henri");
+    underTest.insert(db.getSession(), dto);
+    db.getSession().commit();
+  }
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/compute/AnalysisReportDaoTest.java b/sonar-db/src/test/java/org/sonar/db/compute/AnalysisReportDaoTest.java
deleted file mode 100644 (file)
index 0b93ee6..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.db.compute;
-
-import java.util.List;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.db.compute.AnalysisReportDto.Status.PENDING;
-import static org.sonar.db.compute.AnalysisReportDto.Status.WORKING;
-
-@Category(DbTests.class)
-public class AnalysisReportDaoTest {
-
-  static final String DEFAULT_PROJECT_KEY = "123456789-987654321";
-
-  static System2 system2 = mock(System2.class);
-  @Rule
-  public DbTester db = DbTester.create(system2);
-  DbSession session;
-
-  AnalysisReportDao underTest = new AnalysisReportDao(system2);
-
-  @Before
-  public void setUp() {
-    session = db.getSession();
-  }
-
-  @Test
-  public void insert_multiple_reports() {
-    db.prepareDbUnit(getClass(), "empty.xml");
-    when(system2.now()).thenReturn(1_500_000_000_000L);
-
-    AnalysisReportDto report1 = new AnalysisReportDto().setProjectKey("ProjectKey1").setProjectName("Project 1").setUuid("UUID_1").setStatus(PENDING);
-    AnalysisReportDto report2 = new AnalysisReportDto().setProjectKey("ProjectKey2").setProjectName("Project 2").setUuid("UUID_2").setStatus(PENDING);
-
-    underTest.insert(session, report1);
-    underTest.insert(session, report2);
-    session.commit();
-
-    db.assertDbUnit(getClass(), "insert-result.xml", "analysis_reports");
-  }
-
-  @Test
-  public void resetAllToPendingStatus() {
-    db.prepareDbUnit(getClass(), "update-all-to-status-pending.xml");
-
-    underTest.resetAllToPendingStatus(session);
-    session.commit();
-
-    db.assertDbUnit(getClass(), "update-all-to-status-pending-result.xml", "analysis_reports");
-  }
-
-  @Test
-  public void truncate() {
-    db.prepareDbUnit(getClass(), "any-analysis-reports.xml");
-
-    underTest.truncate(session);
-    session.commit();
-
-    db.assertDbUnit(getClass(), "truncate-result.xml", "analysis_reports");
-  }
-
-  @Test
-  public void find_one_report_by_project_key() {
-    db.prepareDbUnit(getClass(), "select.xml");
-
-    final String projectKey = "123456789-987654321";
-    List<AnalysisReportDto> reports = underTest.selectByProjectKey(session, projectKey);
-    AnalysisReportDto report = reports.get(0);
-
-    assertThat(reports).hasSize(1);
-    assertThat(report.getProjectKey()).isEqualTo(projectKey);
-    assertThat(report.getProjectName()).isEqualTo("Project 1");
-    assertThat(report.getStatus()).isEqualTo(AnalysisReportDto.Status.WORKING);
-    assertThat(report.getId()).isEqualTo(1);
-  }
-
-  @Test
-  public void find_several_reports_by_project_key() {
-    db.prepareDbUnit(getClass(), "select.xml");
-
-    final String projectKey = "987654321-123456789";
-    List<AnalysisReportDto> reports = underTest.selectByProjectKey(session, projectKey);
-
-    assertThat(reports).hasSize(2);
-  }
-
-  @Test
-  public void pop_oldest_pending() {
-    db.prepareDbUnit(getClass(), "pop_oldest_pending.xml");
-
-    AnalysisReportDto nextAvailableReport = underTest.pop(session);
-
-    assertThat(nextAvailableReport.getId()).isEqualTo(3);
-    assertThat(nextAvailableReport.getProjectKey()).isEqualTo("P2");
-  }
-
-  @Test
-  public void count_pending() {
-    db.prepareDbUnit(getClass(), "pop_oldest_pending.xml");
-
-    assertThat(underTest.countPending(db.getSession())).isEqualTo(2);
-  }
-
-  @Test
-  public void pop_null_if_no_pending_reports() {
-    db.prepareDbUnit(getClass(), "pop_null_if_no_pending_reports.xml");
-
-    AnalysisReportDto nextAvailableReport = underTest.pop(session);
-
-    assertThat(nextAvailableReport).isNull();
-  }
-
-  @Test
-  public void getById_maps_all_the_fields_except_the_data() {
-    db.prepareDbUnit(getClass(), "one_analysis_report.xml");
-
-    AnalysisReportDto report = underTest.selectById(session, 1L);
-
-    assertThat(report.getProjectKey()).isEqualTo(DEFAULT_PROJECT_KEY);
-    assertThat(report.getCreatedAt()).isEqualTo(1_500_000_000_001L);
-    assertThat(report.getUpdatedAt()).isEqualTo(1_500_000_000_002L);
-    assertThat(report.getStartedAt()).isEqualTo(1_500_000_000_003L);
-    assertThat(report.getFinishedAt()).isEqualTo(1_500_000_000_004L);
-    assertThat(report.getStatus()).isEqualTo(WORKING);
-  }
-
-  @Test
-  public void getById_returns_null_when_id_not_found() {
-    db.prepareDbUnit(getClass(), "select.xml");
-
-    AnalysisReportDto report = underTest.selectById(session, 4L);
-
-    assertThat(report).isNull();
-  }
-
-  @Test
-  public void delete_one_analysis_report() {
-    db.prepareDbUnit(getClass(), "one_analysis_report.xml");
-
-    underTest.delete(session, 1);
-    session.commit();
-
-    db.assertDbUnit(getClass(), "truncate-result.xml", "analysis_reports");
-  }
-
-  @Test
-  public void findAll_one_analysis_report() {
-    db.prepareDbUnit(getClass(), "one_analysis_report.xml");
-
-    List<AnalysisReportDto> reports = underTest.selectAll(session);
-
-    assertThat(reports).hasSize(1);
-  }
-
-  @Test
-  public void findAll_empty_table() {
-    db.prepareDbUnit(getClass(), "empty.xml");
-
-    List<AnalysisReportDto> reports = underTest.selectAll(session);
-
-    assertThat(reports).isEmpty();
-  }
-
-  @Test
-  public void findAll_three_analysis_reports() {
-    db.prepareDbUnit(getClass(), "three_analysis_reports.xml");
-
-    List<AnalysisReportDto> reports = underTest.selectAll(session);
-
-    assertThat(reports).hasSize(3);
-  }
-}
diff --git a/sonar-db/src/test/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivitiesTest.java b/sonar-db/src/test/java/org/sonar/db/version/v52/RemoveAnalysisReportsFromActivitiesTest.java
new file mode 100644 (file)
index 0000000..0a474ef
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.db.version.v52;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.activity.ActivityDto;
+import org.sonar.db.version.MigrationStep;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RemoveAnalysisReportsFromActivitiesTest {
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  MigrationStep underTest = new RemoveAnalysisReportsFromActivities(db.database());
+
+  @Test
+  public void test() throws Exception {
+    db.getDbClient().activityDao().insert(new ActivityDto().setType("ANALYSIS_REPORT").setKey("1"));
+    db.getDbClient().activityDao().insert(new ActivityDto().setType("ANALYSIS_REPORT").setKey("2"));
+    db.getDbClient().activityDao().insert(new ActivityDto().setType("PROFILE_CHANGE").setKey("3"));
+
+    underTest.execute();
+
+    assertThat(db.countRowsOfTable("ACTIVITIES")).isEqualTo(1);
+  }
+}
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/any-analysis-reports.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/any-analysis-reports.xml
deleted file mode 100644 (file)
index dba17d0..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      uuid="REPORT_1"
-      project_key="123456789-987654321"
-      report_status="WORKING"
-      created_at="1411509600000"
-      updated_at="1411509600000"
-      />
-  <analysis_reports
-      id="2"
-      uuid="REPORT_2"
-      project_key="123456789-987654321"
-      report_status="WORKING"
-      created_at="1411596000000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="3"
-      uuid="REPORT_3"
-      project_key="123456789-987654321"
-      report_status="PENDING"
-      created_at="1411682400000"
-      updated_at="1411682400000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/book_available_report_analysis_while_having_one_working_on_another_project.xml
deleted file mode 100644 (file)
index ae28bef..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="123456789-987654321"
-      uuid="REPORT_1"
-      report_status="PENDING"
-      created_at="1411509600000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="2"
-      project_key="987654321-123456789"
-      uuid="REPORT_2"
-      report_status="WORKING"
-      created_at="1411423200000"
-      updated_at="1411682400000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/empty.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/empty.xml
deleted file mode 100644 (file)
index 871dedc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<dataset>
-
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/insert-result.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/insert-result.xml
deleted file mode 100644 (file)
index d25e364..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="ProjectKey1"
-      project_name="Project 1"
-      uuid="UUID_1"
-      report_status="PENDING"
-      started_at="[null]"
-      finished_at="[null]"
-      created_at="1500000000000"
-      updated_at="1500000000000"
-      />
-  <analysis_reports
-      id="2"
-      project_key="ProjectKey2"
-      project_name="Project 2"
-      uuid="UUID_2"
-      report_status="PENDING"
-      started_at="[null]"
-      finished_at="[null]"
-      created_at="1500000000000"
-      updated_at="1500000000000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/one_analysis_report.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/one_analysis_report.xml
deleted file mode 100644 (file)
index c38ac12..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="123456789-987654321"
-      uuid="REPORT_1"
-      report_status="WORKING"
-      created_at="1500000000001"
-      updated_at="1500000000002"
-      started_at="1500000000003"
-      finished_at="1500000000004"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_null_if_no_pending_reports.xml
deleted file mode 100644 (file)
index 82f93e9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="111111111-987654321"
-      uuid="UUID_1"
-      report_status="WORKING"
-      created_at="1411596000000"
-      updated_at="1411682400000"
-      />
-  <analysis_reports
-      id="2"
-      project_key="123456789-987654321"
-      uuid="UUID_2"
-      report_status="WORKING"
-      created_at="1411509600000"
-      updated_at="1411682400000"
-      />
-  <!-- not select as the previous report which is working is on the same project -->
-  <analysis_reports
-      id="3"
-      project_key="123456789-987654321"
-      uuid="UUID_3"
-      report_status="PENDING"
-      created_at="1411596000000"
-      updated_at="1411682400000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_oldest_pending.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/pop_oldest_pending.xml
deleted file mode 100644 (file)
index 972fde8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<dataset>
-  <!-- WORKING -->
-  <analysis_reports
-    id="1"
-    project_key="P1"
-    uuid="UUID_1"
-    report_status="WORKING"
-    created_at="1411596000000"
-    updated_at="1411682400000"
-    />
-
-  <!-- PENDING on P1, which is already being WORKING-->
-  <analysis_reports
-    id="2"
-    project_key="P1"
-    uuid="UUID_2"
-    report_status="PENDING"
-    created_at="1411509600000"
-    updated_at="1411682400000"
-    />
-  <analysis_reports
-    id="3"
-    project_key="P2"
-    uuid="UUID_3"
-    report_status="PENDING"
-    created_at="1411596000000"
-    updated_at="1411682400000"
-    />
-  <analysis_reports
-    id="4"
-    project_key="P2"
-    uuid="UUID_4"
-    report_status="PENDING"
-    created_at="1420066800000"
-    updated_at="1420066800000"
-    />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/select.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/select.xml
deleted file mode 100644 (file)
index de9d5b9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="123456789-987654321"
-      project_name="Project 1"
-      uuid="UUID_1"
-      report_status="WORKING"
-      created_at="1411509600000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="2"
-      project_key="987654321-123456789"
-      project_name="Project 2"
-      uuid="UUID_2"
-      report_status="WORKING"
-      created_at="1411596000000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="3"
-      project_key="987654321-123456789"
-      project_name="Project 2"
-      uuid="UUID_3"
-      report_status="PENDING"
-      created_at="1411682400000"
-      updated_at="1411682400000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/three_analysis_reports.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/three_analysis_reports.xml
deleted file mode 100644 (file)
index c1e3284..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="123456789-987654321"
-      uuid="UUID_1"
-      report_status="WORKING"
-      created_at="1411509600000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="2"
-      project_key="987654321-123456789"
-      uuid="UUID_2"
-      report_status="WORKING"
-      created_at="1411596000000"
-      updated_at="1411596000000"
-      />
-  <analysis_reports
-      id="3"
-      project_key="987654321-123456789"
-      uuid="UUID_3"
-      report_status="PENDING"
-      created_at="1411682400000"
-      updated_at="1411682400000"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/truncate-result.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/truncate-result.xml
deleted file mode 100644 (file)
index e573e0c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<dataset>
-  <analysis_reports/>
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending-result.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending-result.xml
deleted file mode 100644 (file)
index 16fb8dc..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<dataset>
-    <!-- all rows are PENDING, updated_at is now, started_at is null -->
-    <analysis_reports
-      id="1"
-      project_key="P1"
-      project_name="Project1"
-      uuid="UUID_1"
-      report_status="PENDING"
-      created_at="1411509600000"
-      updated_at="1500000000000"
-      started_at="[null]"
-      finished_at="[null]"
-      />
-    <analysis_reports
-      id="2"
-      project_key="P2"
-      project_name="Project2"
-      uuid="UUID_2"
-      report_status="PENDING"
-      created_at="1411596000000"
-      updated_at="1500000000000"
-      started_at="[null]"
-      finished_at="[null]"
-      />
-    <analysis_reports
-      id="3"
-      project_key="P1"
-      project_name="Project1"
-      uuid="UUID_3"
-      report_status="PENDING"
-      created_at="1411682400000"
-      updated_at="1500000000000"
-      started_at="[null]"
-      finished_at="[null]"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending.xml b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/update-all-to-status-pending.xml
deleted file mode 100644 (file)
index a630cb4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<dataset>
-  <analysis_reports
-      id="1"
-      project_key="P1"
-      project_name="Project1"
-      uuid="UUID_1"
-      report_status="WORKING"
-      created_at="1411509600000"
-      updated_at="1411509600000"
-      started_at="1411509600000"
-      finished_at="[null]"
-      />
-  <analysis_reports
-      id="2"
-      project_key="P2"
-      project_name="Project2"
-      uuid="UUID_2"
-      report_status="WORKING"
-      created_at="1411596000000"
-      updated_at="1411596000000"
-      started_at="1411509600000"
-      finished_at="[null]"
-      />
-  <analysis_reports
-      id="3"
-      project_key="P1"
-      project_name="Project1"
-      uuid="UUID_3"
-      report_status="PENDING"
-      created_at="1411682400000"
-      updated_at="1411682400000"
-      started_at="[null]"
-      finished_at="[null]"
-      />
-</dataset>
diff --git a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/zip.zip b/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/zip.zip
deleted file mode 100644 (file)
index a540bc5..0000000
Binary files a/sonar-db/src/test/resources/org/sonar/db/compute/AnalysisReportDaoTest/zip.zip and /dev/null differ
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/TestSystem2.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/TestSystem2.java
new file mode 100644 (file)
index 0000000..5a68da2
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.api.utils.internal;
+
+import org.sonar.api.utils.System2;
+
+public class TestSystem2 extends System2 {
+
+  private long now = 0L;
+
+  public TestSystem2 setNow(long l) {
+    this.now = l;
+    return this;
+  }
+
+  @Override
+  public long now() {
+    if (now <= 0L) {
+      throw new IllegalStateException("Method setNow() was not called by test");
+    }
+    return now;
+  }
+}
diff --git a/sonar-ws/src/main/gen-java/org/sonarqube/ws/WsCe.java b/sonar-ws/src/main/gen-java/org/sonarqube/ws/WsCe.java
new file mode 100644 (file)
index 0000000..0ddc591
--- /dev/null
@@ -0,0 +1,4898 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: ws-ce.proto
+
+package org.sonarqube.ws;
+
+public final class WsCe {
+  private WsCe() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+  }
+  /**
+   * Protobuf enum {@code sonarqube.ws.ce.TaskStatus}
+   */
+  public enum TaskStatus
+      implements com.google.protobuf.ProtocolMessageEnum {
+    /**
+     * <code>PENDING = 0;</code>
+     */
+    PENDING(0, 0),
+    /**
+     * <code>IN_PROGRESS = 1;</code>
+     */
+    IN_PROGRESS(1, 1),
+    /**
+     * <code>SUCCESS = 2;</code>
+     */
+    SUCCESS(2, 2),
+    /**
+     * <code>FAILED = 3;</code>
+     */
+    FAILED(3, 3),
+    /**
+     * <code>CANCELED = 4;</code>
+     */
+    CANCELED(4, 4),
+    ;
+
+    /**
+     * <code>PENDING = 0;</code>
+     */
+    public static final int PENDING_VALUE = 0;
+    /**
+     * <code>IN_PROGRESS = 1;</code>
+     */
+    public static final int IN_PROGRESS_VALUE = 1;
+    /**
+     * <code>SUCCESS = 2;</code>
+     */
+    public static final int SUCCESS_VALUE = 2;
+    /**
+     * <code>FAILED = 3;</code>
+     */
+    public static final int FAILED_VALUE = 3;
+    /**
+     * <code>CANCELED = 4;</code>
+     */
+    public static final int CANCELED_VALUE = 4;
+
+
+    public final int getNumber() {
+      return value;
+    }
+
+    public static TaskStatus valueOf(int value) {
+      switch (value) {
+        case 0: return PENDING;
+        case 1: return IN_PROGRESS;
+        case 2: return SUCCESS;
+        case 3: return FAILED;
+        case 4: return CANCELED;
+        default: return null;
+      }
+    }
+
+    public static com.google.protobuf.Internal.EnumLiteMap<TaskStatus>
+        internalGetValueMap() {
+      return internalValueMap;
+    }
+    private static com.google.protobuf.Internal.EnumLiteMap<TaskStatus>
+        internalValueMap =
+          new com.google.protobuf.Internal.EnumLiteMap<TaskStatus>() {
+            public TaskStatus findValueByNumber(int number) {
+              return TaskStatus.valueOf(number);
+            }
+          };
+
+    public final com.google.protobuf.Descriptors.EnumValueDescriptor
+        getValueDescriptor() {
+      return getDescriptor().getValues().get(index);
+    }
+    public final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptorForType() {
+      return getDescriptor();
+    }
+    public static final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.getDescriptor().getEnumTypes().get(0);
+    }
+
+    private static final TaskStatus[] VALUES = values();
+
+    public static TaskStatus valueOf(
+        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+      if (desc.getType() != getDescriptor()) {
+        throw new java.lang.IllegalArgumentException(
+          "EnumValueDescriptor is not for this type.");
+      }
+      return VALUES[desc.getIndex()];
+    }
+
+    private final int index;
+    private final int value;
+
+    private TaskStatus(int index, int value) {
+      this.index = index;
+      this.value = value;
+    }
+
+    // @@protoc_insertion_point(enum_scope:sonarqube.ws.ce.TaskStatus)
+  }
+
+  public interface SubmitResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.ce.SubmitResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    boolean hasTaskId();
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    java.lang.String getTaskId();
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getTaskIdBytes();
+
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    boolean hasProjectId();
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    java.lang.String getProjectId();
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getProjectIdBytes();
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.ce.SubmitResponse}
+   *
+   * <pre>
+   * POST api/ce/submit
+   * </pre>
+   */
+  public  static final class SubmitResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.ce.SubmitResponse)
+      SubmitResponseOrBuilder {
+    // Use SubmitResponse.newBuilder() to construct.
+    private SubmitResponse(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private SubmitResponse() {
+      taskId_ = "";
+      projectId_ = "";
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private SubmitResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000001;
+              taskId_ = bs;
+              break;
+            }
+            case 18: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000002;
+              projectId_ = bs;
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_SubmitResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_SubmitResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.WsCe.SubmitResponse.class, org.sonarqube.ws.WsCe.SubmitResponse.Builder.class);
+    }
+
+    private int bitField0_;
+    public static final int TASKID_FIELD_NUMBER = 1;
+    private volatile java.lang.Object taskId_;
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    public boolean hasTaskId() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    public java.lang.String getTaskId() {
+      java.lang.Object ref = taskId_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          taskId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string taskId = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTaskIdBytes() {
+      java.lang.Object ref = taskId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        taskId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int PROJECTID_FIELD_NUMBER = 2;
+    private volatile java.lang.Object projectId_;
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    public boolean hasProjectId() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    public java.lang.String getProjectId() {
+      java.lang.Object ref = projectId_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          projectId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string projectId = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getProjectIdBytes() {
+      java.lang.Object ref = projectId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        projectId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getTaskIdBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBytes(2, getProjectIdBytes());
+      }
+      unknownFields.writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getTaskIdBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getProjectIdBytes());
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.SubmitResponse parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.sonarqube.ws.WsCe.SubmitResponse prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.ce.SubmitResponse}
+     *
+     * <pre>
+     * POST api/ce/submit
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.ce.SubmitResponse)
+        org.sonarqube.ws.WsCe.SubmitResponseOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_SubmitResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_SubmitResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.WsCe.SubmitResponse.class, org.sonarqube.ws.WsCe.SubmitResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.WsCe.SubmitResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        taskId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        projectId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_SubmitResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.WsCe.SubmitResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.WsCe.SubmitResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.WsCe.SubmitResponse build() {
+        org.sonarqube.ws.WsCe.SubmitResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.WsCe.SubmitResponse buildPartial() {
+        org.sonarqube.ws.WsCe.SubmitResponse result = new org.sonarqube.ws.WsCe.SubmitResponse(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.taskId_ = taskId_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.projectId_ = projectId_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.WsCe.SubmitResponse) {
+          return mergeFrom((org.sonarqube.ws.WsCe.SubmitResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.WsCe.SubmitResponse other) {
+        if (other == org.sonarqube.ws.WsCe.SubmitResponse.getDefaultInstance()) return this;
+        if (other.hasTaskId()) {
+          bitField0_ |= 0x00000001;
+          taskId_ = other.taskId_;
+          onChanged();
+        }
+        if (other.hasProjectId()) {
+          bitField0_ |= 0x00000002;
+          projectId_ = other.projectId_;
+          onChanged();
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.WsCe.SubmitResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.WsCe.SubmitResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private java.lang.Object taskId_ = "";
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public boolean hasTaskId() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public java.lang.String getTaskId() {
+        java.lang.Object ref = taskId_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            taskId_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTaskIdBytes() {
+        java.lang.Object ref = taskId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          taskId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public Builder setTaskId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        taskId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public Builder clearTaskId() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        taskId_ = getDefaultInstance().getTaskId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string taskId = 1;</code>
+       */
+      public Builder setTaskIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        taskId_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object projectId_ = "";
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public boolean hasProjectId() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public java.lang.String getProjectId() {
+        java.lang.Object ref = projectId_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            projectId_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getProjectIdBytes() {
+        java.lang.Object ref = projectId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          projectId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public Builder setProjectId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        projectId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public Builder clearProjectId() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        projectId_ = getDefaultInstance().getProjectId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string projectId = 2;</code>
+       */
+      public Builder setProjectIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        projectId_ = value;
+        onChanged();
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.ce.SubmitResponse)
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.ce.SubmitResponse)
+    private static final org.sonarqube.ws.WsCe.SubmitResponse DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.sonarqube.ws.WsCe.SubmitResponse();
+    }
+
+    public static org.sonarqube.ws.WsCe.SubmitResponse getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    public static final com.google.protobuf.Parser<SubmitResponse> PARSER =
+        new com.google.protobuf.AbstractParser<SubmitResponse>() {
+      public SubmitResponse parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new SubmitResponse(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<SubmitResponse> getParserForType() {
+      return PARSER;
+    }
+
+    public org.sonarqube.ws.WsCe.SubmitResponse getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface TaskResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.ce.TaskResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    boolean hasTask();
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    org.sonarqube.ws.WsCe.Task getTask();
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    org.sonarqube.ws.WsCe.TaskOrBuilder getTaskOrBuilder();
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.ce.TaskResponse}
+   *
+   * <pre>
+   * GET api/ce/task
+   * </pre>
+   */
+  public  static final class TaskResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.ce.TaskResponse)
+      TaskResponseOrBuilder {
+    // Use TaskResponse.newBuilder() to construct.
+    private TaskResponse(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private TaskResponse() {
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private TaskResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              org.sonarqube.ws.WsCe.Task.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000001) == 0x00000001)) {
+                subBuilder = task_.toBuilder();
+              }
+              task_ = input.readMessage(org.sonarqube.ws.WsCe.Task.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(task_);
+                task_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000001;
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_TaskResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_TaskResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.WsCe.TaskResponse.class, org.sonarqube.ws.WsCe.TaskResponse.Builder.class);
+    }
+
+    private int bitField0_;
+    public static final int TASK_FIELD_NUMBER = 1;
+    private org.sonarqube.ws.WsCe.Task task_;
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    public boolean hasTask() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    public org.sonarqube.ws.WsCe.Task getTask() {
+      return task_ == null ? org.sonarqube.ws.WsCe.Task.getDefaultInstance() : task_;
+    }
+    /**
+     * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+     */
+    public org.sonarqube.ws.WsCe.TaskOrBuilder getTaskOrBuilder() {
+      return task_ == null ? org.sonarqube.ws.WsCe.Task.getDefaultInstance() : task_;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeMessage(1, getTask());
+      }
+      unknownFields.writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, getTask());
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.TaskResponse parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.sonarqube.ws.WsCe.TaskResponse prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.ce.TaskResponse}
+     *
+     * <pre>
+     * GET api/ce/task
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.ce.TaskResponse)
+        org.sonarqube.ws.WsCe.TaskResponseOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_TaskResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_TaskResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.WsCe.TaskResponse.class, org.sonarqube.ws.WsCe.TaskResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.WsCe.TaskResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getTaskFieldBuilder();
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        if (taskBuilder_ == null) {
+          task_ = null;
+        } else {
+          taskBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_TaskResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.WsCe.TaskResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.WsCe.TaskResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.WsCe.TaskResponse build() {
+        org.sonarqube.ws.WsCe.TaskResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.WsCe.TaskResponse buildPartial() {
+        org.sonarqube.ws.WsCe.TaskResponse result = new org.sonarqube.ws.WsCe.TaskResponse(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        if (taskBuilder_ == null) {
+          result.task_ = task_;
+        } else {
+          result.task_ = taskBuilder_.build();
+        }
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.WsCe.TaskResponse) {
+          return mergeFrom((org.sonarqube.ws.WsCe.TaskResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.WsCe.TaskResponse other) {
+        if (other == org.sonarqube.ws.WsCe.TaskResponse.getDefaultInstance()) return this;
+        if (other.hasTask()) {
+          mergeTask(other.getTask());
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.WsCe.TaskResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.WsCe.TaskResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private org.sonarqube.ws.WsCe.Task task_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> taskBuilder_;
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public boolean hasTask() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task getTask() {
+        if (taskBuilder_ == null) {
+          return task_ == null ? org.sonarqube.ws.WsCe.Task.getDefaultInstance() : task_;
+        } else {
+          return taskBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public Builder setTask(org.sonarqube.ws.WsCe.Task value) {
+        if (taskBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          task_ = value;
+          onChanged();
+        } else {
+          taskBuilder_.setMessage(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public Builder setTask(
+          org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (taskBuilder_ == null) {
+          task_ = builderForValue.build();
+          onChanged();
+        } else {
+          taskBuilder_.setMessage(builderForValue.build());
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public Builder mergeTask(org.sonarqube.ws.WsCe.Task value) {
+        if (taskBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001) &&
+              task_ != null &&
+              task_ != org.sonarqube.ws.WsCe.Task.getDefaultInstance()) {
+            task_ =
+              org.sonarqube.ws.WsCe.Task.newBuilder(task_).mergeFrom(value).buildPartial();
+          } else {
+            task_ = value;
+          }
+          onChanged();
+        } else {
+          taskBuilder_.mergeFrom(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public Builder clearTask() {
+        if (taskBuilder_ == null) {
+          task_ = null;
+          onChanged();
+        } else {
+          taskBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder getTaskBuilder() {
+        bitField0_ |= 0x00000001;
+        onChanged();
+        return getTaskFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.TaskOrBuilder getTaskOrBuilder() {
+        if (taskBuilder_ != null) {
+          return taskBuilder_.getMessageOrBuilder();
+        } else {
+          return task_ == null ?
+              org.sonarqube.ws.WsCe.Task.getDefaultInstance() : task_;
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.Task task = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> 
+          getTaskFieldBuilder() {
+        if (taskBuilder_ == null) {
+          taskBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder>(
+                  getTask(),
+                  getParentForChildren(),
+                  isClean());
+          task_ = null;
+        }
+        return taskBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.ce.TaskResponse)
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.ce.TaskResponse)
+    private static final org.sonarqube.ws.WsCe.TaskResponse DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.sonarqube.ws.WsCe.TaskResponse();
+    }
+
+    public static org.sonarqube.ws.WsCe.TaskResponse getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    public static final com.google.protobuf.Parser<TaskResponse> PARSER =
+        new com.google.protobuf.AbstractParser<TaskResponse>() {
+      public TaskResponse parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new TaskResponse(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<TaskResponse> getParserForType() {
+      return PARSER;
+    }
+
+    public org.sonarqube.ws.WsCe.TaskResponse getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface QueueResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.ce.QueueResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    java.util.List<org.sonarqube.ws.WsCe.Task> 
+        getTasksList();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    org.sonarqube.ws.WsCe.Task getTasks(int index);
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    int getTasksCount();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+        getTasksOrBuilderList();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+        int index);
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.ce.QueueResponse}
+   *
+   * <pre>
+   * GET api/ce/queue
+   * </pre>
+   */
+  public  static final class QueueResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.ce.QueueResponse)
+      QueueResponseOrBuilder {
+    // Use QueueResponse.newBuilder() to construct.
+    private QueueResponse(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private QueueResponse() {
+      tasks_ = java.util.Collections.emptyList();
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private QueueResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+                tasks_ = new java.util.ArrayList<org.sonarqube.ws.WsCe.Task>();
+                mutable_bitField0_ |= 0x00000001;
+              }
+              tasks_.add(input.readMessage(org.sonarqube.ws.WsCe.Task.PARSER, extensionRegistry));
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+          tasks_ = java.util.Collections.unmodifiableList(tasks_);
+        }
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_QueueResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_QueueResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.WsCe.QueueResponse.class, org.sonarqube.ws.WsCe.QueueResponse.Builder.class);
+    }
+
+    public static final int TASKS_FIELD_NUMBER = 1;
+    private java.util.List<org.sonarqube.ws.WsCe.Task> tasks_;
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    public java.util.List<org.sonarqube.ws.WsCe.Task> getTasksList() {
+      return tasks_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    public java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+        getTasksOrBuilderList() {
+      return tasks_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    public int getTasksCount() {
+      return tasks_.size();
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    public org.sonarqube.ws.WsCe.Task getTasks(int index) {
+      return tasks_.get(index);
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+     */
+    public org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+        int index) {
+      return tasks_.get(index);
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      for (int i = 0; i < tasks_.size(); i++) {
+        output.writeMessage(1, tasks_.get(i));
+      }
+      unknownFields.writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      for (int i = 0; i < tasks_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, tasks_.get(i));
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.QueueResponse parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.sonarqube.ws.WsCe.QueueResponse prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.ce.QueueResponse}
+     *
+     * <pre>
+     * GET api/ce/queue
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.ce.QueueResponse)
+        org.sonarqube.ws.WsCe.QueueResponseOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_QueueResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_QueueResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.WsCe.QueueResponse.class, org.sonarqube.ws.WsCe.QueueResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.WsCe.QueueResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getTasksFieldBuilder();
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        if (tasksBuilder_ == null) {
+          tasks_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          tasksBuilder_.clear();
+        }
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_QueueResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.WsCe.QueueResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.WsCe.QueueResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.WsCe.QueueResponse build() {
+        org.sonarqube.ws.WsCe.QueueResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.WsCe.QueueResponse buildPartial() {
+        org.sonarqube.ws.WsCe.QueueResponse result = new org.sonarqube.ws.WsCe.QueueResponse(this);
+        int from_bitField0_ = bitField0_;
+        if (tasksBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001)) {
+            tasks_ = java.util.Collections.unmodifiableList(tasks_);
+            bitField0_ = (bitField0_ & ~0x00000001);
+          }
+          result.tasks_ = tasks_;
+        } else {
+          result.tasks_ = tasksBuilder_.build();
+        }
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.WsCe.QueueResponse) {
+          return mergeFrom((org.sonarqube.ws.WsCe.QueueResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.WsCe.QueueResponse other) {
+        if (other == org.sonarqube.ws.WsCe.QueueResponse.getDefaultInstance()) return this;
+        if (tasksBuilder_ == null) {
+          if (!other.tasks_.isEmpty()) {
+            if (tasks_.isEmpty()) {
+              tasks_ = other.tasks_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+            } else {
+              ensureTasksIsMutable();
+              tasks_.addAll(other.tasks_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.tasks_.isEmpty()) {
+            if (tasksBuilder_.isEmpty()) {
+              tasksBuilder_.dispose();
+              tasksBuilder_ = null;
+              tasks_ = other.tasks_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+              tasksBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getTasksFieldBuilder() : null;
+            } else {
+              tasksBuilder_.addAllMessages(other.tasks_);
+            }
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.WsCe.QueueResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.WsCe.QueueResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private java.util.List<org.sonarqube.ws.WsCe.Task> tasks_ =
+        java.util.Collections.emptyList();
+      private void ensureTasksIsMutable() {
+        if (!((bitField0_ & 0x00000001) == 0x00000001)) {
+          tasks_ = new java.util.ArrayList<org.sonarqube.ws.WsCe.Task>(tasks_);
+          bitField0_ |= 0x00000001;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> tasksBuilder_;
+
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public java.util.List<org.sonarqube.ws.WsCe.Task> getTasksList() {
+        if (tasksBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(tasks_);
+        } else {
+          return tasksBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public int getTasksCount() {
+        if (tasksBuilder_ == null) {
+          return tasks_.size();
+        } else {
+          return tasksBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task getTasks(int index) {
+        if (tasksBuilder_ == null) {
+          return tasks_.get(index);
+        } else {
+          return tasksBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder setTasks(
+          int index, org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.set(index, value);
+          onChanged();
+        } else {
+          tasksBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder setTasks(
+          int index, org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder addTasks(org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.add(value);
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder addTasks(
+          int index, org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.add(index, value);
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder addTasks(
+          org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.add(builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder addTasks(
+          int index, org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder addAllTasks(
+          java.lang.Iterable<? extends org.sonarqube.ws.WsCe.Task> values) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, tasks_);
+          onChanged();
+        } else {
+          tasksBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder clearTasks() {
+        if (tasksBuilder_ == null) {
+          tasks_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+          onChanged();
+        } else {
+          tasksBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public Builder removeTasks(int index) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.remove(index);
+          onChanged();
+        } else {
+          tasksBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder getTasksBuilder(
+          int index) {
+        return getTasksFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+          int index) {
+        if (tasksBuilder_ == null) {
+          return tasks_.get(index);  } else {
+          return tasksBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+           getTasksOrBuilderList() {
+        if (tasksBuilder_ != null) {
+          return tasksBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(tasks_);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder addTasksBuilder() {
+        return getTasksFieldBuilder().addBuilder(
+            org.sonarqube.ws.WsCe.Task.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder addTasksBuilder(
+          int index) {
+        return getTasksFieldBuilder().addBuilder(
+            index, org.sonarqube.ws.WsCe.Task.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 1;</code>
+       */
+      public java.util.List<org.sonarqube.ws.WsCe.Task.Builder> 
+           getTasksBuilderList() {
+        return getTasksFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> 
+          getTasksFieldBuilder() {
+        if (tasksBuilder_ == null) {
+          tasksBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder>(
+                  tasks_,
+                  ((bitField0_ & 0x00000001) == 0x00000001),
+                  getParentForChildren(),
+                  isClean());
+          tasks_ = null;
+        }
+        return tasksBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.ce.QueueResponse)
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.ce.QueueResponse)
+    private static final org.sonarqube.ws.WsCe.QueueResponse DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.sonarqube.ws.WsCe.QueueResponse();
+    }
+
+    public static org.sonarqube.ws.WsCe.QueueResponse getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    public static final com.google.protobuf.Parser<QueueResponse> PARSER =
+        new com.google.protobuf.AbstractParser<QueueResponse>() {
+      public QueueResponse parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new QueueResponse(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<QueueResponse> getParserForType() {
+      return PARSER;
+    }
+
+    public org.sonarqube.ws.WsCe.QueueResponse getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface ActivityResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.ce.ActivityResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    boolean hasPaging();
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    org.sonarqube.ws.Common.Paging getPaging();
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    org.sonarqube.ws.Common.PagingOrBuilder getPagingOrBuilder();
+
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    java.util.List<org.sonarqube.ws.WsCe.Task> 
+        getTasksList();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    org.sonarqube.ws.WsCe.Task getTasks(int index);
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    int getTasksCount();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+        getTasksOrBuilderList();
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+        int index);
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.ce.ActivityResponse}
+   *
+   * <pre>
+   * GET api/ce/activity
+   * </pre>
+   */
+  public  static final class ActivityResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.ce.ActivityResponse)
+      ActivityResponseOrBuilder {
+    // Use ActivityResponse.newBuilder() to construct.
+    private ActivityResponse(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private ActivityResponse() {
+      tasks_ = java.util.Collections.emptyList();
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private ActivityResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              org.sonarqube.ws.Common.Paging.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000001) == 0x00000001)) {
+                subBuilder = paging_.toBuilder();
+              }
+              paging_ = input.readMessage(org.sonarqube.ws.Common.Paging.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(paging_);
+                paging_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000001;
+              break;
+            }
+            case 18: {
+              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+                tasks_ = new java.util.ArrayList<org.sonarqube.ws.WsCe.Task>();
+                mutable_bitField0_ |= 0x00000002;
+              }
+              tasks_.add(input.readMessage(org.sonarqube.ws.WsCe.Task.PARSER, extensionRegistry));
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+          tasks_ = java.util.Collections.unmodifiableList(tasks_);
+        }
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_ActivityResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_ActivityResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.WsCe.ActivityResponse.class, org.sonarqube.ws.WsCe.ActivityResponse.Builder.class);
+    }
+
+    private int bitField0_;
+    public static final int PAGING_FIELD_NUMBER = 1;
+    private org.sonarqube.ws.Common.Paging paging_;
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    public boolean hasPaging() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    public org.sonarqube.ws.Common.Paging getPaging() {
+      return paging_ == null ? org.sonarqube.ws.Common.Paging.getDefaultInstance() : paging_;
+    }
+    /**
+     * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+     */
+    public org.sonarqube.ws.Common.PagingOrBuilder getPagingOrBuilder() {
+      return paging_ == null ? org.sonarqube.ws.Common.Paging.getDefaultInstance() : paging_;
+    }
+
+    public static final int TASKS_FIELD_NUMBER = 2;
+    private java.util.List<org.sonarqube.ws.WsCe.Task> tasks_;
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    public java.util.List<org.sonarqube.ws.WsCe.Task> getTasksList() {
+      return tasks_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    public java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+        getTasksOrBuilderList() {
+      return tasks_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    public int getTasksCount() {
+      return tasks_.size();
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    public org.sonarqube.ws.WsCe.Task getTasks(int index) {
+      return tasks_.get(index);
+    }
+    /**
+     * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+     */
+    public org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+        int index) {
+      return tasks_.get(index);
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeMessage(1, getPaging());
+      }
+      for (int i = 0; i < tasks_.size(); i++) {
+        output.writeMessage(2, tasks_.get(i));
+      }
+      unknownFields.writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, getPaging());
+      }
+      for (int i = 0; i < tasks_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, tasks_.get(i));
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.ActivityResponse parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.sonarqube.ws.WsCe.ActivityResponse prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.ce.ActivityResponse}
+     *
+     * <pre>
+     * GET api/ce/activity
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.ce.ActivityResponse)
+        org.sonarqube.ws.WsCe.ActivityResponseOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_ActivityResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_ActivityResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.WsCe.ActivityResponse.class, org.sonarqube.ws.WsCe.ActivityResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.WsCe.ActivityResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getPagingFieldBuilder();
+          getTasksFieldBuilder();
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        if (pagingBuilder_ == null) {
+          paging_ = null;
+        } else {
+          pagingBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        if (tasksBuilder_ == null) {
+          tasks_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+        } else {
+          tasksBuilder_.clear();
+        }
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_ActivityResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.WsCe.ActivityResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.WsCe.ActivityResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.WsCe.ActivityResponse build() {
+        org.sonarqube.ws.WsCe.ActivityResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.WsCe.ActivityResponse buildPartial() {
+        org.sonarqube.ws.WsCe.ActivityResponse result = new org.sonarqube.ws.WsCe.ActivityResponse(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        if (pagingBuilder_ == null) {
+          result.paging_ = paging_;
+        } else {
+          result.paging_ = pagingBuilder_.build();
+        }
+        if (tasksBuilder_ == null) {
+          if (((bitField0_ & 0x00000002) == 0x00000002)) {
+            tasks_ = java.util.Collections.unmodifiableList(tasks_);
+            bitField0_ = (bitField0_ & ~0x00000002);
+          }
+          result.tasks_ = tasks_;
+        } else {
+          result.tasks_ = tasksBuilder_.build();
+        }
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.WsCe.ActivityResponse) {
+          return mergeFrom((org.sonarqube.ws.WsCe.ActivityResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.WsCe.ActivityResponse other) {
+        if (other == org.sonarqube.ws.WsCe.ActivityResponse.getDefaultInstance()) return this;
+        if (other.hasPaging()) {
+          mergePaging(other.getPaging());
+        }
+        if (tasksBuilder_ == null) {
+          if (!other.tasks_.isEmpty()) {
+            if (tasks_.isEmpty()) {
+              tasks_ = other.tasks_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+            } else {
+              ensureTasksIsMutable();
+              tasks_.addAll(other.tasks_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.tasks_.isEmpty()) {
+            if (tasksBuilder_.isEmpty()) {
+              tasksBuilder_.dispose();
+              tasksBuilder_ = null;
+              tasks_ = other.tasks_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+              tasksBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getTasksFieldBuilder() : null;
+            } else {
+              tasksBuilder_.addAllMessages(other.tasks_);
+            }
+          }
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.WsCe.ActivityResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.WsCe.ActivityResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private org.sonarqube.ws.Common.Paging paging_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.Common.Paging, org.sonarqube.ws.Common.Paging.Builder, org.sonarqube.ws.Common.PagingOrBuilder> pagingBuilder_;
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public boolean hasPaging() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public org.sonarqube.ws.Common.Paging getPaging() {
+        if (pagingBuilder_ == null) {
+          return paging_ == null ? org.sonarqube.ws.Common.Paging.getDefaultInstance() : paging_;
+        } else {
+          return pagingBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public Builder setPaging(org.sonarqube.ws.Common.Paging value) {
+        if (pagingBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          paging_ = value;
+          onChanged();
+        } else {
+          pagingBuilder_.setMessage(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public Builder setPaging(
+          org.sonarqube.ws.Common.Paging.Builder builderForValue) {
+        if (pagingBuilder_ == null) {
+          paging_ = builderForValue.build();
+          onChanged();
+        } else {
+          pagingBuilder_.setMessage(builderForValue.build());
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public Builder mergePaging(org.sonarqube.ws.Common.Paging value) {
+        if (pagingBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001) &&
+              paging_ != null &&
+              paging_ != org.sonarqube.ws.Common.Paging.getDefaultInstance()) {
+            paging_ =
+              org.sonarqube.ws.Common.Paging.newBuilder(paging_).mergeFrom(value).buildPartial();
+          } else {
+            paging_ = value;
+          }
+          onChanged();
+        } else {
+          pagingBuilder_.mergeFrom(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public Builder clearPaging() {
+        if (pagingBuilder_ == null) {
+          paging_ = null;
+          onChanged();
+        } else {
+          pagingBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public org.sonarqube.ws.Common.Paging.Builder getPagingBuilder() {
+        bitField0_ |= 0x00000001;
+        onChanged();
+        return getPagingFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      public org.sonarqube.ws.Common.PagingOrBuilder getPagingOrBuilder() {
+        if (pagingBuilder_ != null) {
+          return pagingBuilder_.getMessageOrBuilder();
+        } else {
+          return paging_ == null ?
+              org.sonarqube.ws.Common.Paging.getDefaultInstance() : paging_;
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.commons.Paging paging = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.Common.Paging, org.sonarqube.ws.Common.Paging.Builder, org.sonarqube.ws.Common.PagingOrBuilder> 
+          getPagingFieldBuilder() {
+        if (pagingBuilder_ == null) {
+          pagingBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.sonarqube.ws.Common.Paging, org.sonarqube.ws.Common.Paging.Builder, org.sonarqube.ws.Common.PagingOrBuilder>(
+                  getPaging(),
+                  getParentForChildren(),
+                  isClean());
+          paging_ = null;
+        }
+        return pagingBuilder_;
+      }
+
+      private java.util.List<org.sonarqube.ws.WsCe.Task> tasks_ =
+        java.util.Collections.emptyList();
+      private void ensureTasksIsMutable() {
+        if (!((bitField0_ & 0x00000002) == 0x00000002)) {
+          tasks_ = new java.util.ArrayList<org.sonarqube.ws.WsCe.Task>(tasks_);
+          bitField0_ |= 0x00000002;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> tasksBuilder_;
+
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public java.util.List<org.sonarqube.ws.WsCe.Task> getTasksList() {
+        if (tasksBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(tasks_);
+        } else {
+          return tasksBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public int getTasksCount() {
+        if (tasksBuilder_ == null) {
+          return tasks_.size();
+        } else {
+          return tasksBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task getTasks(int index) {
+        if (tasksBuilder_ == null) {
+          return tasks_.get(index);
+        } else {
+          return tasksBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder setTasks(
+          int index, org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.set(index, value);
+          onChanged();
+        } else {
+          tasksBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder setTasks(
+          int index, org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder addTasks(org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.add(value);
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder addTasks(
+          int index, org.sonarqube.ws.WsCe.Task value) {
+        if (tasksBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureTasksIsMutable();
+          tasks_.add(index, value);
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder addTasks(
+          org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.add(builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder addTasks(
+          int index, org.sonarqube.ws.WsCe.Task.Builder builderForValue) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          tasksBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder addAllTasks(
+          java.lang.Iterable<? extends org.sonarqube.ws.WsCe.Task> values) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, tasks_);
+          onChanged();
+        } else {
+          tasksBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder clearTasks() {
+        if (tasksBuilder_ == null) {
+          tasks_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+          onChanged();
+        } else {
+          tasksBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public Builder removeTasks(int index) {
+        if (tasksBuilder_ == null) {
+          ensureTasksIsMutable();
+          tasks_.remove(index);
+          onChanged();
+        } else {
+          tasksBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder getTasksBuilder(
+          int index) {
+        return getTasksFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public org.sonarqube.ws.WsCe.TaskOrBuilder getTasksOrBuilder(
+          int index) {
+        if (tasksBuilder_ == null) {
+          return tasks_.get(index);  } else {
+          return tasksBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public java.util.List<? extends org.sonarqube.ws.WsCe.TaskOrBuilder> 
+           getTasksOrBuilderList() {
+        if (tasksBuilder_ != null) {
+          return tasksBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(tasks_);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder addTasksBuilder() {
+        return getTasksFieldBuilder().addBuilder(
+            org.sonarqube.ws.WsCe.Task.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public org.sonarqube.ws.WsCe.Task.Builder addTasksBuilder(
+          int index) {
+        return getTasksFieldBuilder().addBuilder(
+            index, org.sonarqube.ws.WsCe.Task.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.ce.Task tasks = 2;</code>
+       */
+      public java.util.List<org.sonarqube.ws.WsCe.Task.Builder> 
+           getTasksBuilderList() {
+        return getTasksFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder> 
+          getTasksFieldBuilder() {
+        if (tasksBuilder_ == null) {
+          tasksBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonarqube.ws.WsCe.Task, org.sonarqube.ws.WsCe.Task.Builder, org.sonarqube.ws.WsCe.TaskOrBuilder>(
+                  tasks_,
+                  ((bitField0_ & 0x00000002) == 0x00000002),
+                  getParentForChildren(),
+                  isClean());
+          tasks_ = null;
+        }
+        return tasksBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.ce.ActivityResponse)
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.ce.ActivityResponse)
+    private static final org.sonarqube.ws.WsCe.ActivityResponse DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.sonarqube.ws.WsCe.ActivityResponse();
+    }
+
+    public static org.sonarqube.ws.WsCe.ActivityResponse getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    public static final com.google.protobuf.Parser<ActivityResponse> PARSER =
+        new com.google.protobuf.AbstractParser<ActivityResponse>() {
+      public ActivityResponse parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new ActivityResponse(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<ActivityResponse> getParserForType() {
+      return PARSER;
+    }
+
+    public org.sonarqube.ws.WsCe.ActivityResponse getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface TaskOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.ce.Task)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    boolean hasId();
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    java.lang.String getId();
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getIdBytes();
+
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    boolean hasTaskType();
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    java.lang.String getTaskType();
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getTaskTypeBytes();
+
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    boolean hasComponentId();
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    java.lang.String getComponentId();
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    com.google.protobuf.ByteString
+        getComponentIdBytes();
+
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    boolean hasComponentKey();
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    java.lang.String getComponentKey();
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    com.google.protobuf.ByteString
+        getComponentKeyBytes();
+
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    boolean hasComponentName();
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    java.lang.String getComponentName();
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    com.google.protobuf.ByteString
+        getComponentNameBytes();
+
+    /**
+     * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+     */
+    boolean hasStatus();
+    /**
+     * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+     */
+    org.sonarqube.ws.WsCe.TaskStatus getStatus();
+
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    boolean hasSubmittedAt();
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    java.lang.String getSubmittedAt();
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    com.google.protobuf.ByteString
+        getSubmittedAtBytes();
+
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    boolean hasSubmitterLogin();
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    java.lang.String getSubmitterLogin();
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    com.google.protobuf.ByteString
+        getSubmitterLoginBytes();
+
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    boolean hasStartedAt();
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    java.lang.String getStartedAt();
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    com.google.protobuf.ByteString
+        getStartedAtBytes();
+
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    boolean hasFinishedAt();
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    java.lang.String getFinishedAt();
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    com.google.protobuf.ByteString
+        getFinishedAtBytes();
+
+    /**
+     * <code>optional bool isLastFinished = 11;</code>
+     */
+    boolean hasIsLastFinished();
+    /**
+     * <code>optional bool isLastFinished = 11;</code>
+     */
+    boolean getIsLastFinished();
+
+    /**
+     * <code>optional int64 executionTimeMs = 12;</code>
+     */
+    boolean hasExecutionTimeMs();
+    /**
+     * <code>optional int64 executionTimeMs = 12;</code>
+     */
+    long getExecutionTimeMs();
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.ce.Task}
+   */
+  public  static final class Task extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.ce.Task)
+      TaskOrBuilder {
+    // Use Task.newBuilder() to construct.
+    private Task(com.google.protobuf.GeneratedMessage.Builder builder) {
+      super(builder);
+    }
+    private Task() {
+      id_ = "";
+      taskType_ = "";
+      componentId_ = "";
+      componentKey_ = "";
+      componentName_ = "";
+      status_ = 0;
+      submittedAt_ = "";
+      submitterLogin_ = "";
+      startedAt_ = "";
+      finishedAt_ = "";
+      isLastFinished_ = false;
+      executionTimeMs_ = 0L;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return this.unknownFields;
+    }
+    private Task(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000001;
+              id_ = bs;
+              break;
+            }
+            case 18: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000002;
+              taskType_ = bs;
+              break;
+            }
+            case 26: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000004;
+              componentId_ = bs;
+              break;
+            }
+            case 34: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000008;
+              componentKey_ = bs;
+              break;
+            }
+            case 42: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000010;
+              componentName_ = bs;
+              break;
+            }
+            case 48: {
+              int rawValue = input.readEnum();
+              org.sonarqube.ws.WsCe.TaskStatus value = org.sonarqube.ws.WsCe.TaskStatus.valueOf(rawValue);
+              if (value == null) {
+                unknownFields.mergeVarintField(6, rawValue);
+              } else {
+                bitField0_ |= 0x00000020;
+                status_ = rawValue;
+              }
+              break;
+            }
+            case 58: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000040;
+              submittedAt_ = bs;
+              break;
+            }
+            case 66: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000080;
+              submitterLogin_ = bs;
+              break;
+            }
+            case 74: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000100;
+              startedAt_ = bs;
+              break;
+            }
+            case 82: {
+              com.google.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000200;
+              finishedAt_ = bs;
+              break;
+            }
+            case 88: {
+              bitField0_ |= 0x00000400;
+              isLastFinished_ = input.readBool();
+              break;
+            }
+            case 96: {
+              bitField0_ |= 0x00000800;
+              executionTimeMs_ = input.readInt64();
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_Task_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_Task_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.WsCe.Task.class, org.sonarqube.ws.WsCe.Task.Builder.class);
+    }
+
+    private int bitField0_;
+    public static final int ID_FIELD_NUMBER = 1;
+    private volatile java.lang.Object id_;
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    public boolean hasId() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    public java.lang.String getId() {
+      java.lang.Object ref = id_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          id_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string id = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getIdBytes() {
+      java.lang.Object ref = id_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        id_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int TASKTYPE_FIELD_NUMBER = 2;
+    private volatile java.lang.Object taskType_;
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    public boolean hasTaskType() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    public java.lang.String getTaskType() {
+      java.lang.Object ref = taskType_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          taskType_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string taskType = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTaskTypeBytes() {
+      java.lang.Object ref = taskType_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        taskType_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int COMPONENTID_FIELD_NUMBER = 3;
+    private volatile java.lang.Object componentId_;
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    public boolean hasComponentId() {
+      return ((bitField0_ & 0x00000004) == 0x00000004);
+    }
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    public java.lang.String getComponentId() {
+      java.lang.Object ref = componentId_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          componentId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string componentId = 3;</code>
+     */
+    public com.google.protobuf.ByteString
+        getComponentIdBytes() {
+      java.lang.Object ref = componentId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        componentId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int COMPONENTKEY_FIELD_NUMBER = 4;
+    private volatile java.lang.Object componentKey_;
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    public boolean hasComponentKey() {
+      return ((bitField0_ & 0x00000008) == 0x00000008);
+    }
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    public java.lang.String getComponentKey() {
+      java.lang.Object ref = componentKey_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          componentKey_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string componentKey = 4;</code>
+     */
+    public com.google.protobuf.ByteString
+        getComponentKeyBytes() {
+      java.lang.Object ref = componentKey_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        componentKey_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int COMPONENTNAME_FIELD_NUMBER = 5;
+    private volatile java.lang.Object componentName_;
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    public boolean hasComponentName() {
+      return ((bitField0_ & 0x00000010) == 0x00000010);
+    }
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    public java.lang.String getComponentName() {
+      java.lang.Object ref = componentName_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          componentName_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string componentName = 5;</code>
+     */
+    public com.google.protobuf.ByteString
+        getComponentNameBytes() {
+      java.lang.Object ref = componentName_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        componentName_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int STATUS_FIELD_NUMBER = 6;
+    private int status_;
+    /**
+     * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+     */
+    public boolean hasStatus() {
+      return ((bitField0_ & 0x00000020) == 0x00000020);
+    }
+    /**
+     * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+     */
+    public org.sonarqube.ws.WsCe.TaskStatus getStatus() {
+      org.sonarqube.ws.WsCe.TaskStatus result = org.sonarqube.ws.WsCe.TaskStatus.valueOf(status_);
+      return result == null ? org.sonarqube.ws.WsCe.TaskStatus.PENDING : result;
+    }
+
+    public static final int SUBMITTEDAT_FIELD_NUMBER = 7;
+    private volatile java.lang.Object submittedAt_;
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    public boolean hasSubmittedAt() {
+      return ((bitField0_ & 0x00000040) == 0x00000040);
+    }
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    public java.lang.String getSubmittedAt() {
+      java.lang.Object ref = submittedAt_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          submittedAt_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string submittedAt = 7;</code>
+     */
+    public com.google.protobuf.ByteString
+        getSubmittedAtBytes() {
+      java.lang.Object ref = submittedAt_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        submittedAt_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int SUBMITTERLOGIN_FIELD_NUMBER = 8;
+    private volatile java.lang.Object submitterLogin_;
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    public boolean hasSubmitterLogin() {
+      return ((bitField0_ & 0x00000080) == 0x00000080);
+    }
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    public java.lang.String getSubmitterLogin() {
+      java.lang.Object ref = submitterLogin_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          submitterLogin_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string submitterLogin = 8;</code>
+     */
+    public com.google.protobuf.ByteString
+        getSubmitterLoginBytes() {
+      java.lang.Object ref = submitterLogin_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        submitterLogin_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int STARTEDAT_FIELD_NUMBER = 9;
+    private volatile java.lang.Object startedAt_;
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    public boolean hasStartedAt() {
+      return ((bitField0_ & 0x00000100) == 0x00000100);
+    }
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    public java.lang.String getStartedAt() {
+      java.lang.Object ref = startedAt_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          startedAt_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string startedAt = 9;</code>
+     */
+    public com.google.protobuf.ByteString
+        getStartedAtBytes() {
+      java.lang.Object ref = startedAt_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        startedAt_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int FINISHEDAT_FIELD_NUMBER = 10;
+    private volatile java.lang.Object finishedAt_;
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    public boolean hasFinishedAt() {
+      return ((bitField0_ & 0x00000200) == 0x00000200);
+    }
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    public java.lang.String getFinishedAt() {
+      java.lang.Object ref = finishedAt_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          finishedAt_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string finishedAt = 10;</code>
+     */
+    public com.google.protobuf.ByteString
+        getFinishedAtBytes() {
+      java.lang.Object ref = finishedAt_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        finishedAt_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int ISLASTFINISHED_FIELD_NUMBER = 11;
+    private boolean isLastFinished_;
+    /**
+     * <code>optional bool isLastFinished = 11;</code>
+     */
+    public boolean hasIsLastFinished() {
+      return ((bitField0_ & 0x00000400) == 0x00000400);
+    }
+    /**
+     * <code>optional bool isLastFinished = 11;</code>
+     */
+    public boolean getIsLastFinished() {
+      return isLastFinished_;
+    }
+
+    public static final int EXECUTIONTIMEMS_FIELD_NUMBER = 12;
+    private long executionTimeMs_;
+    /**
+     * <code>optional int64 executionTimeMs = 12;</code>
+     */
+    public boolean hasExecutionTimeMs() {
+      return ((bitField0_ & 0x00000800) == 0x00000800);
+    }
+    /**
+     * <code>optional int64 executionTimeMs = 12;</code>
+     */
+    public long getExecutionTimeMs() {
+      return executionTimeMs_;
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getIdBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBytes(2, getTaskTypeBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        output.writeBytes(3, getComponentIdBytes());
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        output.writeBytes(4, getComponentKeyBytes());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        output.writeBytes(5, getComponentNameBytes());
+      }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        output.writeEnum(6, status_);
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeBytes(7, getSubmittedAtBytes());
+      }
+      if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        output.writeBytes(8, getSubmitterLoginBytes());
+      }
+      if (((bitField0_ & 0x00000100) == 0x00000100)) {
+        output.writeBytes(9, getStartedAtBytes());
+      }
+      if (((bitField0_ & 0x00000200) == 0x00000200)) {
+        output.writeBytes(10, getFinishedAtBytes());
+      }
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
+        output.writeBool(11, isLastFinished_);
+      }
+      if (((bitField0_ & 0x00000800) == 0x00000800)) {
+        output.writeInt64(12, executionTimeMs_);
+      }
+      unknownFields.writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getIdBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getTaskTypeBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(3, getComponentIdBytes());
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(4, getComponentKeyBytes());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(5, getComponentNameBytes());
+      }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(6, status_);
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(7, getSubmittedAtBytes());
+      }
+      if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(8, getSubmitterLoginBytes());
+      }
+      if (((bitField0_ & 0x00000100) == 0x00000100)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(9, getStartedAtBytes());
+      }
+      if (((bitField0_ & 0x00000200) == 0x00000200)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(10, getFinishedAtBytes());
+      }
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(11, isLastFinished_);
+      }
+      if (((bitField0_ & 0x00000800) == 0x00000800)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(12, executionTimeMs_);
+      }
+      size += unknownFields.getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.WsCe.Task parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.sonarqube.ws.WsCe.Task prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.ce.Task}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.ce.Task)
+        org.sonarqube.ws.WsCe.TaskOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_Task_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_Task_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.WsCe.Task.class, org.sonarqube.ws.WsCe.Task.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.WsCe.Task.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        id_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        taskType_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        componentId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000004);
+        componentKey_ = "";
+        bitField0_ = (bitField0_ & ~0x00000008);
+        componentName_ = "";
+        bitField0_ = (bitField0_ & ~0x00000010);
+        status_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000020);
+        submittedAt_ = "";
+        bitField0_ = (bitField0_ & ~0x00000040);
+        submitterLogin_ = "";
+        bitField0_ = (bitField0_ & ~0x00000080);
+        startedAt_ = "";
+        bitField0_ = (bitField0_ & ~0x00000100);
+        finishedAt_ = "";
+        bitField0_ = (bitField0_ & ~0x00000200);
+        isLastFinished_ = false;
+        bitField0_ = (bitField0_ & ~0x00000400);
+        executionTimeMs_ = 0L;
+        bitField0_ = (bitField0_ & ~0x00000800);
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.WsCe.internal_static_sonarqube_ws_ce_Task_descriptor;
+      }
+
+      public org.sonarqube.ws.WsCe.Task getDefaultInstanceForType() {
+        return org.sonarqube.ws.WsCe.Task.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.WsCe.Task build() {
+        org.sonarqube.ws.WsCe.Task result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.WsCe.Task buildPartial() {
+        org.sonarqube.ws.WsCe.Task result = new org.sonarqube.ws.WsCe.Task(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.id_ = id_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.taskType_ = taskType_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000004;
+        }
+        result.componentId_ = componentId_;
+        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+          to_bitField0_ |= 0x00000008;
+        }
+        result.componentKey_ = componentKey_;
+        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+          to_bitField0_ |= 0x00000010;
+        }
+        result.componentName_ = componentName_;
+        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+          to_bitField0_ |= 0x00000020;
+        }
+        result.status_ = status_;
+        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+          to_bitField0_ |= 0x00000040;
+        }
+        result.submittedAt_ = submittedAt_;
+        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
+          to_bitField0_ |= 0x00000080;
+        }
+        result.submitterLogin_ = submitterLogin_;
+        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
+          to_bitField0_ |= 0x00000100;
+        }
+        result.startedAt_ = startedAt_;
+        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {
+          to_bitField0_ |= 0x00000200;
+        }
+        result.finishedAt_ = finishedAt_;
+        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
+          to_bitField0_ |= 0x00000400;
+        }
+        result.isLastFinished_ = isLastFinished_;
+        if (((from_bitField0_ & 0x00000800) == 0x00000800)) {
+          to_bitField0_ |= 0x00000800;
+        }
+        result.executionTimeMs_ = executionTimeMs_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.WsCe.Task) {
+          return mergeFrom((org.sonarqube.ws.WsCe.Task)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.WsCe.Task other) {
+        if (other == org.sonarqube.ws.WsCe.Task.getDefaultInstance()) return this;
+        if (other.hasId()) {
+          bitField0_ |= 0x00000001;
+          id_ = other.id_;
+          onChanged();
+        }
+        if (other.hasTaskType()) {
+          bitField0_ |= 0x00000002;
+          taskType_ = other.taskType_;
+          onChanged();
+        }
+        if (other.hasComponentId()) {
+          bitField0_ |= 0x00000004;
+          componentId_ = other.componentId_;
+          onChanged();
+        }
+        if (other.hasComponentKey()) {
+          bitField0_ |= 0x00000008;
+          componentKey_ = other.componentKey_;
+          onChanged();
+        }
+        if (other.hasComponentName()) {
+          bitField0_ |= 0x00000010;
+          componentName_ = other.componentName_;
+          onChanged();
+        }
+        if (other.hasStatus()) {
+          setStatus(other.getStatus());
+        }
+        if (other.hasSubmittedAt()) {
+          bitField0_ |= 0x00000040;
+          submittedAt_ = other.submittedAt_;
+          onChanged();
+        }
+        if (other.hasSubmitterLogin()) {
+          bitField0_ |= 0x00000080;
+          submitterLogin_ = other.submitterLogin_;
+          onChanged();
+        }
+        if (other.hasStartedAt()) {
+          bitField0_ |= 0x00000100;
+          startedAt_ = other.startedAt_;
+          onChanged();
+        }
+        if (other.hasFinishedAt()) {
+          bitField0_ |= 0x00000200;
+          finishedAt_ = other.finishedAt_;
+          onChanged();
+        }
+        if (other.hasIsLastFinished()) {
+          setIsLastFinished(other.getIsLastFinished());
+        }
+        if (other.hasExecutionTimeMs()) {
+          setExecutionTimeMs(other.getExecutionTimeMs());
+        }
+        this.mergeUnknownFields(other.unknownFields);
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.WsCe.Task parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.WsCe.Task) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private java.lang.Object id_ = "";
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public boolean hasId() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public java.lang.String getId() {
+        java.lang.Object ref = id_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            id_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getIdBytes() {
+        java.lang.Object ref = id_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          id_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public Builder setId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        id_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public Builder clearId() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        id_ = getDefaultInstance().getId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string id = 1;</code>
+       */
+      public Builder setIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        id_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object taskType_ = "";
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public boolean hasTaskType() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public java.lang.String getTaskType() {
+        java.lang.Object ref = taskType_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            taskType_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTaskTypeBytes() {
+        java.lang.Object ref = taskType_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          taskType_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public Builder setTaskType(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        taskType_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public Builder clearTaskType() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        taskType_ = getDefaultInstance().getTaskType();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string taskType = 2;</code>
+       */
+      public Builder setTaskTypeBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        taskType_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object componentId_ = "";
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public boolean hasComponentId() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public java.lang.String getComponentId() {
+        java.lang.Object ref = componentId_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            componentId_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public com.google.protobuf.ByteString
+          getComponentIdBytes() {
+        java.lang.Object ref = componentId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          componentId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public Builder setComponentId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        componentId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public Builder clearComponentId() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        componentId_ = getDefaultInstance().getComponentId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentId = 3;</code>
+       */
+      public Builder setComponentIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        componentId_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object componentKey_ = "";
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public boolean hasComponentKey() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
+      }
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public java.lang.String getComponentKey() {
+        java.lang.Object ref = componentKey_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            componentKey_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public com.google.protobuf.ByteString
+          getComponentKeyBytes() {
+        java.lang.Object ref = componentKey_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          componentKey_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public Builder setComponentKey(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        componentKey_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public Builder clearComponentKey() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        componentKey_ = getDefaultInstance().getComponentKey();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentKey = 4;</code>
+       */
+      public Builder setComponentKeyBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000008;
+        componentKey_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object componentName_ = "";
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public boolean hasComponentName() {
+        return ((bitField0_ & 0x00000010) == 0x00000010);
+      }
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public java.lang.String getComponentName() {
+        java.lang.Object ref = componentName_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            componentName_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public com.google.protobuf.ByteString
+          getComponentNameBytes() {
+        java.lang.Object ref = componentName_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          componentName_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public Builder setComponentName(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000010;
+        componentName_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public Builder clearComponentName() {
+        bitField0_ = (bitField0_ & ~0x00000010);
+        componentName_ = getDefaultInstance().getComponentName();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string componentName = 5;</code>
+       */
+      public Builder setComponentNameBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000010;
+        componentName_ = value;
+        onChanged();
+        return this;
+      }
+
+      private int status_ = 0;
+      /**
+       * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+       */
+      public boolean hasStatus() {
+        return ((bitField0_ & 0x00000020) == 0x00000020);
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+       */
+      public org.sonarqube.ws.WsCe.TaskStatus getStatus() {
+        org.sonarqube.ws.WsCe.TaskStatus result = org.sonarqube.ws.WsCe.TaskStatus.valueOf(status_);
+        return result == null ? org.sonarqube.ws.WsCe.TaskStatus.PENDING : result;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+       */
+      public Builder setStatus(org.sonarqube.ws.WsCe.TaskStatus value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        bitField0_ |= 0x00000020;
+        status_ = value.getNumber();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.ce.TaskStatus status = 6;</code>
+       */
+      public Builder clearStatus() {
+        bitField0_ = (bitField0_ & ~0x00000020);
+        status_ = 0;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object submittedAt_ = "";
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public boolean hasSubmittedAt() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
+      }
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public java.lang.String getSubmittedAt() {
+        java.lang.Object ref = submittedAt_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            submittedAt_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public com.google.protobuf.ByteString
+          getSubmittedAtBytes() {
+        java.lang.Object ref = submittedAt_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          submittedAt_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public Builder setSubmittedAt(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000040;
+        submittedAt_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public Builder clearSubmittedAt() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        submittedAt_ = getDefaultInstance().getSubmittedAt();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string submittedAt = 7;</code>
+       */
+      public Builder setSubmittedAtBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000040;
+        submittedAt_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object submitterLogin_ = "";
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public boolean hasSubmitterLogin() {
+        return ((bitField0_ & 0x00000080) == 0x00000080);
+      }
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public java.lang.String getSubmitterLogin() {
+        java.lang.Object ref = submitterLogin_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            submitterLogin_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public com.google.protobuf.ByteString
+          getSubmitterLoginBytes() {
+        java.lang.Object ref = submitterLogin_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          submitterLogin_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public Builder setSubmitterLogin(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000080;
+        submitterLogin_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public Builder clearSubmitterLogin() {
+        bitField0_ = (bitField0_ & ~0x00000080);
+        submitterLogin_ = getDefaultInstance().getSubmitterLogin();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string submitterLogin = 8;</code>
+       */
+      public Builder setSubmitterLoginBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000080;
+        submitterLogin_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object startedAt_ = "";
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public boolean hasStartedAt() {
+        return ((bitField0_ & 0x00000100) == 0x00000100);
+      }
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public java.lang.String getStartedAt() {
+        java.lang.Object ref = startedAt_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            startedAt_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public com.google.protobuf.ByteString
+          getStartedAtBytes() {
+        java.lang.Object ref = startedAt_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          startedAt_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public Builder setStartedAt(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000100;
+        startedAt_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public Builder clearStartedAt() {
+        bitField0_ = (bitField0_ & ~0x00000100);
+        startedAt_ = getDefaultInstance().getStartedAt();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string startedAt = 9;</code>
+       */
+      public Builder setStartedAtBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000100;
+        startedAt_ = value;
+        onChanged();
+        return this;
+      }
+
+      private java.lang.Object finishedAt_ = "";
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public boolean hasFinishedAt() {
+        return ((bitField0_ & 0x00000200) == 0x00000200);
+      }
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public java.lang.String getFinishedAt() {
+        java.lang.Object ref = finishedAt_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            finishedAt_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public com.google.protobuf.ByteString
+          getFinishedAtBytes() {
+        java.lang.Object ref = finishedAt_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          finishedAt_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public Builder setFinishedAt(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000200;
+        finishedAt_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public Builder clearFinishedAt() {
+        bitField0_ = (bitField0_ & ~0x00000200);
+        finishedAt_ = getDefaultInstance().getFinishedAt();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string finishedAt = 10;</code>
+       */
+      public Builder setFinishedAtBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000200;
+        finishedAt_ = value;
+        onChanged();
+        return this;
+      }
+
+      private boolean isLastFinished_ ;
+      /**
+       * <code>optional bool isLastFinished = 11;</code>
+       */
+      public boolean hasIsLastFinished() {
+        return ((bitField0_ & 0x00000400) == 0x00000400);
+      }
+      /**
+       * <code>optional bool isLastFinished = 11;</code>
+       */
+      public boolean getIsLastFinished() {
+        return isLastFinished_;
+      }
+      /**
+       * <code>optional bool isLastFinished = 11;</code>
+       */
+      public Builder setIsLastFinished(boolean value) {
+        bitField0_ |= 0x00000400;
+        isLastFinished_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool isLastFinished = 11;</code>
+       */
+      public Builder clearIsLastFinished() {
+        bitField0_ = (bitField0_ & ~0x00000400);
+        isLastFinished_ = false;
+        onChanged();
+        return this;
+      }
+
+      private long executionTimeMs_ ;
+      /**
+       * <code>optional int64 executionTimeMs = 12;</code>
+       */
+      public boolean hasExecutionTimeMs() {
+        return ((bitField0_ & 0x00000800) == 0x00000800);
+      }
+      /**
+       * <code>optional int64 executionTimeMs = 12;</code>
+       */
+      public long getExecutionTimeMs() {
+        return executionTimeMs_;
+      }
+      /**
+       * <code>optional int64 executionTimeMs = 12;</code>
+       */
+      public Builder setExecutionTimeMs(long value) {
+        bitField0_ |= 0x00000800;
+        executionTimeMs_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int64 executionTimeMs = 12;</code>
+       */
+      public Builder clearExecutionTimeMs() {
+        bitField0_ = (bitField0_ & ~0x00000800);
+        executionTimeMs_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.ce.Task)
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.ce.Task)
+    private static final org.sonarqube.ws.WsCe.Task DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.sonarqube.ws.WsCe.Task();
+    }
+
+    public static org.sonarqube.ws.WsCe.Task getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    public static final com.google.protobuf.Parser<Task> PARSER =
+        new com.google.protobuf.AbstractParser<Task>() {
+      public Task parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new Task(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Task> getParserForType() {
+      return PARSER;
+    }
+
+    public org.sonarqube.ws.WsCe.Task getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_ce_SubmitResponse_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_ce_SubmitResponse_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_ce_TaskResponse_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_ce_TaskResponse_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_ce_QueueResponse_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_ce_QueueResponse_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_ce_ActivityResponse_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_ce_ActivityResponse_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_ce_Task_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_ce_Task_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n\013ws-ce.proto\022\017sonarqube.ws.ce\032\020ws-commo" +
+      "ns.proto\"3\n\016SubmitResponse\022\016\n\006taskId\030\001 \001" +
+      "(\t\022\021\n\tprojectId\030\002 \001(\t\"3\n\014TaskResponse\022#\n" +
+      "\004task\030\001 \001(\0132\025.sonarqube.ws.ce.Task\"5\n\rQu" +
+      "eueResponse\022$\n\005tasks\030\001 \003(\0132\025.sonarqube.w" +
+      "s.ce.Task\"f\n\020ActivityResponse\022,\n\006paging\030" +
+      "\001 \001(\0132\034.sonarqube.ws.commons.Paging\022$\n\005t" +
+      "asks\030\002 \003(\0132\025.sonarqube.ws.ce.Task\"\230\002\n\004Ta" +
+      "sk\022\n\n\002id\030\001 \001(\t\022\020\n\010taskType\030\002 \001(\t\022\023\n\013comp" +
+      "onentId\030\003 \001(\t\022\024\n\014componentKey\030\004 \001(\t\022\025\n\rc",
+      "omponentName\030\005 \001(\t\022+\n\006status\030\006 \001(\0162\033.son" +
+      "arqube.ws.ce.TaskStatus\022\023\n\013submittedAt\030\007" +
+      " \001(\t\022\026\n\016submitterLogin\030\010 \001(\t\022\021\n\tstartedA" +
+      "t\030\t \001(\t\022\022\n\nfinishedAt\030\n \001(\t\022\026\n\016isLastFin" +
+      "ished\030\013 \001(\010\022\027\n\017executionTimeMs\030\014 \001(\003*Q\n\n" +
+      "TaskStatus\022\013\n\007PENDING\020\000\022\017\n\013IN_PROGRESS\020\001" +
+      "\022\013\n\007SUCCESS\020\002\022\n\n\006FAILED\020\003\022\014\n\010CANCELED\020\004B" +
+      "\032\n\020org.sonarqube.wsB\004WsCeH\001"
+    };
+    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
+          public com.google.protobuf.ExtensionRegistry assignDescriptors(
+              com.google.protobuf.Descriptors.FileDescriptor root) {
+            descriptor = root;
+            return null;
+          }
+        };
+    com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+          org.sonarqube.ws.Common.getDescriptor(),
+        }, assigner);
+    internal_static_sonarqube_ws_ce_SubmitResponse_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_sonarqube_ws_ce_SubmitResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_ce_SubmitResponse_descriptor,
+        new java.lang.String[] { "TaskId", "ProjectId", });
+    internal_static_sonarqube_ws_ce_TaskResponse_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_sonarqube_ws_ce_TaskResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_ce_TaskResponse_descriptor,
+        new java.lang.String[] { "Task", });
+    internal_static_sonarqube_ws_ce_QueueResponse_descriptor =
+      getDescriptor().getMessageTypes().get(2);
+    internal_static_sonarqube_ws_ce_QueueResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_ce_QueueResponse_descriptor,
+        new java.lang.String[] { "Tasks", });
+    internal_static_sonarqube_ws_ce_ActivityResponse_descriptor =
+      getDescriptor().getMessageTypes().get(3);
+    internal_static_sonarqube_ws_ce_ActivityResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_ce_ActivityResponse_descriptor,
+        new java.lang.String[] { "Paging", "Tasks", });
+    internal_static_sonarqube_ws_ce_Task_descriptor =
+      getDescriptor().getMessageTypes().get(4);
+    internal_static_sonarqube_ws_ce_Task_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_ce_Task_descriptor,
+        new java.lang.String[] { "Id", "TaskType", "ComponentId", "ComponentKey", "ComponentName", "Status", "SubmittedAt", "SubmitterLogin", "StartedAt", "FinishedAt", "IsLastFinished", "ExecutionTimeMs", });
+    org.sonarqube.ws.Common.getDescriptor();
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/sonar-ws/src/main/protobuf/ws-ce.proto b/sonar-ws/src/main/protobuf/ws-ce.proto
new file mode 100644 (file)
index 0000000..fa558dd
--- /dev/null
@@ -0,0 +1,72 @@
+// SonarQube, open source software quality management tool.
+// Copyright (C) 2008-2015 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.
+
+syntax = "proto2";
+
+package sonarqube.ws.ce;
+
+import "ws-commons.proto";
+
+option java_package = "org.sonarqube.ws";
+option java_outer_classname = "WsCe";
+option optimize_for = SPEED;
+
+// POST api/ce/submit
+message SubmitResponse {
+  optional string taskId = 1;
+  optional string projectId = 2;
+}
+
+// GET api/ce/task
+message TaskResponse {
+  optional Task task = 1;
+}
+
+// GET api/ce/queue
+message QueueResponse {
+  repeated Task tasks = 1;
+}
+
+// GET api/ce/activity
+message ActivityResponse {
+  optional sonarqube.ws.commons.Paging paging = 1;
+  repeated Task tasks = 2;
+}
+
+message Task {
+  optional string id = 1;
+  optional string taskType = 2;
+  optional string componentId = 3;
+  optional string componentKey = 4;
+  optional string componentName = 5;
+  optional TaskStatus status = 6;
+  optional string submittedAt = 7;
+  optional string submitterLogin = 8;
+  optional string startedAt = 9;
+  optional string finishedAt = 10;
+  optional bool isLastFinished = 11;
+  optional int64 executionTimeMs = 12;
+}
+
+enum TaskStatus {
+  PENDING = 0;
+  IN_PROGRESS = 1;
+  SUCCESS = 2;
+  FAILED = 3;
+  CANCELED = 4;
+}