@Test
  public void testOneRun() throws Exception {
    fillInRepo();

    final int countTotalBefore =
        countFiles(snapshots, new String[] {"**/maven-metadata.xml"}, new String[] {".nexus/**"});

    RebuildMavenMetadataTask task =
        nexusScheduler.createTaskInstance( //
            RebuildMavenMetadataTask.class);

    task.setRepositoryId(snapshots.getId());

    ScheduledTask<Object> handle = nexusScheduler.submit("task", task);

    // block until it finishes
    handle.get();

    // count it again
    final int countTotalAfter =
        countFiles(snapshots, new String[] {"**/maven-metadata.xml"}, new String[] {".nexus/**"});

    // assert
    assertTrue(
        "We should have more md's after rebuilding them, since we have some of them missing!",
        countTotalBefore < countTotalAfter);
  }
  protected <T> String getNextRunTime(ScheduledTask<T> task) {
    String nextRunTime = "n/a";

    // Run now type tasks should never have a next run time
    if (!task.getSchedule().getClass().isAssignableFrom(RunNowSchedule.class)
        && task.getNextRun() != null) {
      nextRunTime = task.getNextRun().toString();
    }

    return nextRunTime;
  }
  @Override
  public boolean allowConcurrentSubmission(Map<String, List<ScheduledTask<?>>> activeTasks) {
    if (activeTasks.containsKey(ID)) {
      for (ScheduledTask<?> scheduledTask : activeTasks.get(ID)) {
        if (isSubmitted(scheduledTask)
            && conflictsWith((GenerateMetadataTask) scheduledTask.getTask())
            && scheduledTask.getSchedule() instanceof RunNowSchedule) {
          throw new TaskAlreadyScheduledException(
              scheduledTask, "Found same task in scheduler queue.");
        }
      }
    }

    return true;
  }
  @Override
  public boolean allowConcurrentExecution(Map<String, List<ScheduledTask<?>>> activeTasks) {

    if (activeTasks.containsKey(ID)) {
      int activeRunningTasks = 0;
      for (ScheduledTask<?> scheduledTask : activeTasks.get(ID)) {
        if (RUNNING.equals(scheduledTask.getTaskState())) {
          if (conflictsWith((GenerateMetadataTask) scheduledTask.getTask())) {
            return false;
          }
          activeRunningTasks++;
        }
      }
      return activeRunningTasks < yumRegistry.maxNumberOfParallelThreads();
    }

    return true;
  }
  public <T> ScheduledServiceBaseResource getServiceRestModel(ScheduledTask<T> task) {
    ScheduledServiceBaseResource resource = null;

    if (RunNowSchedule.class.isAssignableFrom(task.getSchedule().getClass())
        || ManualRunSchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceBaseResource();
    } else if (OnceSchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceOnceResource();

      OnceSchedule taskSchedule = (OnceSchedule) task.getSchedule();
      ScheduledServiceOnceResource res = (ScheduledServiceOnceResource) resource;

      res.setStartDate(formatDate(taskSchedule.getStartDate()));
      res.setStartTime(formatTime(taskSchedule.getStartDate()));
    } else if (HourlySchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceHourlyResource();

      HourlySchedule taskSchedule = (HourlySchedule) task.getSchedule();
      ScheduledServiceHourlyResource res = (ScheduledServiceHourlyResource) resource;

      res.setStartDate(formatDate(taskSchedule.getStartDate()));
      res.setStartTime(formatTime(taskSchedule.getStartDate()));
    } else if (DailySchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceDailyResource();

      DailySchedule taskSchedule = (DailySchedule) task.getSchedule();
      ScheduledServiceDailyResource res = (ScheduledServiceDailyResource) resource;

      res.setStartDate(formatDate(taskSchedule.getStartDate()));
      res.setRecurringTime(formatTime(taskSchedule.getStartDate()));
    } else if (WeeklySchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceWeeklyResource();

      WeeklySchedule taskSchedule = (WeeklySchedule) task.getSchedule();
      ScheduledServiceWeeklyResource res = (ScheduledServiceWeeklyResource) resource;

      res.setStartDate(formatDate(taskSchedule.getStartDate()));
      res.setRecurringTime(formatTime(taskSchedule.getStartDate()));
      res.setRecurringDay(formatRecurringDayOfWeek(taskSchedule.getDaysToRun()));
    } else if (MonthlySchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceMonthlyResource();

      MonthlySchedule taskSchedule = (MonthlySchedule) task.getSchedule();
      ScheduledServiceMonthlyResource res = (ScheduledServiceMonthlyResource) resource;

      res.setStartDate(formatDate(taskSchedule.getStartDate()));
      res.setRecurringTime(formatTime(taskSchedule.getStartDate()));
      res.setRecurringDay(formatRecurringDayOfMonth(taskSchedule.getDaysToRun()));
    } else if (CronSchedule.class.isAssignableFrom(task.getSchedule().getClass())) {
      resource = new ScheduledServiceAdvancedResource();

      CronSchedule taskSchedule = (CronSchedule) task.getSchedule();
      ScheduledServiceAdvancedResource res = (ScheduledServiceAdvancedResource) resource;

      res.setCronCommand(taskSchedule.getCronString());
    }

    if (resource != null) {
      resource.setId(task.getId());
      resource.setEnabled(task.isEnabled());
      resource.setName(task.getName());
      resource.setSchedule(getScheduleShortName(task.getSchedule()));
      resource.setTypeId(task.getType());
      resource.setProperties(formatServiceProperties(task.getTaskParams()));
      resource.setAlertEmail(TaskUtils.getAlertEmail(task));
    }

    return resource;
  }
  @Test
  public void testOneRunWithSubpath() throws Exception {
    fillInRepo();

    // we will initiate a task with "subpath" of /org/sonatype, so we count the files of total and
    // the processed and
    // non-processed set
    // to be able to perform checks at the end
    final int countTotalBefore =
        countFiles(snapshots, new String[] {"**/maven-metadata.xml"}, new String[] {".nexus/**"});
    final int countNonProcessedSubBefore =
        countFiles(
            snapshots,
            new String[] {"**/maven-metadata.xml"},
            new String[] {".nexus/**", "org/sonatype/**/maven-metadata.xml"});
    final int countProcessedSubBefore =
        countFiles(
            snapshots,
            new String[] {"org/sonatype/**/maven-metadata.xml"},
            new String[] {".nexus/**"});

    RebuildMavenMetadataTask task =
        nexusScheduler.createTaskInstance( //
            RebuildMavenMetadataTask.class);

    task.setRepositoryId(snapshots.getId());
    task.setResourceStorePath("/org/sonatype");

    ScheduledTask<Object> handle = nexusScheduler.submit("task", task);

    // block until it finishes
    handle.get();

    // count it again
    final int countTotalAfter =
        countFiles(snapshots, new String[] {"**/maven-metadata.xml"}, new String[] {".nexus/**"});
    final int countNonProcessedSubAfter =
        countFiles(
            snapshots,
            new String[] {"**/maven-metadata.xml"},
            new String[] {".nexus/**", "org/sonatype/**/maven-metadata.xml"});
    final int countProcessedSubAfter =
        countFiles(
            snapshots,
            new String[] {"org/sonatype/**/maven-metadata.xml"},
            new String[] {".nexus/**"});

    // assert
    assertTrue(
        String.format(
            "We should have more md's after rebuilding them, since we have some of them missing! (%s, %s)",
            new Object[] {countTotalBefore, countTotalAfter}),
        countTotalBefore < countTotalAfter);
    assertTrue(
        String.format(
            "We should have same count of md's after rebuilding them for non-processed ones! (%s, %s)",
            new Object[] {countNonProcessedSubBefore, countNonProcessedSubAfter}),
        countNonProcessedSubBefore == countNonProcessedSubAfter);
    assertTrue(
        String.format(
            "We should have more md's after rebuilding them for processed ones, since we have some of them missing! (%s, %s)",
            new Object[] {countProcessedSubBefore, countProcessedSubAfter}),
        countProcessedSubBefore < countProcessedSubAfter);

    // the total change has to equals to processed change
    assertTrue(
        "We should have same change on total level as we have on processed ones, since we have some of them missing!",
        (countTotalAfter - countTotalBefore) == (countProcessedSubAfter - countProcessedSubBefore));
  }
 private boolean isSubmitted(ScheduledTask<?> scheduledTask) {
   return SUBMITTED.equals(scheduledTask.getTaskState())
       || SLEEPING.equals(scheduledTask.getTaskState());
 }
  /** Add a new scheduled service to nexus. */
  @Override
  @POST
  @ResourceMethodSignature(
      input = ScheduledServiceResourceResponse.class,
      output = ScheduledServiceResourceStatusResponse.class)
  public Object post(Context context, Request request, Response response, Object payload)
      throws ResourceException {
    ScheduledServiceResourceResponse serviceRequest = (ScheduledServiceResourceResponse) payload;
    ScheduledServiceResourceStatusResponse result = null;

    if (serviceRequest != null) {
      ScheduledServiceBaseResource serviceResource = serviceRequest.getData();
      try {
        Schedule schedule = getModelSchedule(serviceRequest.getData());
        ScheduledTask<?> task = null;

        if (schedule != null) {
          task =
              getNexusScheduler()
                  .schedule(
                      getModelName(serviceResource),
                      getModelNexusTask(serviceResource, request),
                      schedule);
        } else {
          task =
              getNexusScheduler()
                  .schedule(
                      getModelName(serviceResource),
                      getModelNexusTask(serviceResource, request),
                      new ManualRunSchedule());
        }

        task.setEnabled(serviceResource.isEnabled());

        // Need to store the enabled flag update
        getNexusScheduler().updateSchedule(task);

        ScheduledServiceResourceStatus resourceStatus = new ScheduledServiceResourceStatus();
        resourceStatus.setResource(serviceResource);
        // Just need to update the id, as the incoming data is a POST w/ no id
        resourceStatus.getResource().setId(task.getId());
        resourceStatus.setResourceURI(createChildReference(request, this, task.getId()).toString());
        resourceStatus.setStatus(task.getTaskState().toString());
        resourceStatus.setReadableStatus(getReadableState(task.getTaskState()));
        resourceStatus.setCreated(
            task.getScheduledAt() == null ? "n/a" : task.getScheduledAt().toString());
        resourceStatus.setLastRunResult(
            TaskState.BROKEN.equals(task.getTaskState()) ? "Error" : "Ok");
        resourceStatus.setLastRunTime(
            task.getLastRun() == null ? "n/a" : task.getLastRun().toString());
        resourceStatus.setNextRunTime(
            task.getNextRun() == null ? "n/a" : task.getNextRun().toString());
        if (task.getScheduledAt() != null) {
          resourceStatus.setCreatedInMillis(task.getScheduledAt().getTime());
        }
        if (task.getLastRun() != null) {
          resourceStatus.setLastRunTimeInMillis(task.getLastRun().getTime());
        }
        if (task.getNextRun() != null) {
          resourceStatus.setNextRunTimeInMillis(task.getNextRun().getTime());
        }

        result = new ScheduledServiceResourceStatusResponse();
        result.setData(resourceStatus);
      } catch (RejectedExecutionException e) {
        getLogger().warn("Execution of task " + getModelName(serviceResource) + " rejected.");

        throw new ResourceException(Status.CLIENT_ERROR_CONFLICT, e.getMessage());
      } catch (ParseException e) {
        getLogger().warn("Unable to parse data for task " + getModelName(serviceResource));

        throw new PlexusResourceException(
            Status.CLIENT_ERROR_BAD_REQUEST,
            e.getMessage(),
            getNexusErrorResponse("cronCommand", e.getMessage()));
      } catch (InvalidConfigurationException e) {
        handleConfigurationException(e);
      }
    }
    return result;
  }
  /**
   * Retrieve a list of scheduled tasks currently configured in nexus.
   *
   * @param allTasks If true, will return all tasks, even non-exposed tasks.
   */
  @Override
  @GET
  @ResourceMethodSignature(output = ScheduledServiceListResourceResponse.class)
  public Object get(Context context, Request request, Response response, Variant variant)
      throws ResourceException {
    boolean allTasks = isAllTasks(request);

    Map<String, List<ScheduledTask<?>>> tasksMap = getNexusScheduler().getAllTasks();

    ScheduledServiceListResourceResponse result = new ScheduledServiceListResourceResponse();

    for (String key : tasksMap.keySet()) {
      List<ScheduledTask<?>> tasks = tasksMap.get(key);

      for (ScheduledTask<?> task : tasks) {
        boolean isExposed = true;

        SchedulerTask<?> st = task.getSchedulerTask();

        if (st != null && st instanceof NexusTask<?>) {
          isExposed = ((NexusTask<?>) st).isExposed();
        }

        if (allTasks || isExposed) {
          if (getLogger().isDebugEnabled()) {
            getLogger()
                .debug("Building task '" + task.getName() + "' of type '" + task.getType() + "'.");
          }

          ScheduledServiceListResource item = new ScheduledServiceListResource();
          item.setResourceURI(createChildReference(request, this, task.getId()).toString());
          item.setLastRunResult(getLastRunResult(task));
          item.setId(task.getId());
          item.setName(task.getName());
          item.setStatus(task.getTaskState().toString());
          item.setReadableStatus(getReadableState(task.getTaskState()));
          item.setTypeId(task.getType());
          ScheduledTaskDescriptor descriptor =
              getNexusConfiguration().getScheduledTaskDescriptor(task.getType());
          if (descriptor != null) {
            item.setTypeName(descriptor.getName());
          }
          item.setCreated(task.getScheduledAt() == null ? "n/a" : task.getScheduledAt().toString());
          item.setLastRunTime(task.getLastRun() == null ? "n/a" : task.getLastRun().toString());
          final Date nextRunTime = getNextRunTime(task);
          item.setNextRunTime(nextRunTime == null ? "n/a" : nextRunTime.toString());
          if (task.getScheduledAt() != null) {
            item.setCreatedInMillis(task.getScheduledAt().getTime());
          }
          if (task.getLastRun() != null) {
            item.setLastRunTimeInMillis(task.getLastRun().getTime());
          }
          if (nextRunTime != null) {
            item.setNextRunTimeInMillis(nextRunTime.getTime());
          }
          item.setSchedule(getScheduleShortName(task.getSchedule()));
          item.setEnabled(task.isEnabled());

          result.addData(item);
        }
      }
    }

    return result;
  }