@Override
 public Collection<UpdateWorkerTask> getUpdatingUpdateTasks(
     final long guestId, final Connector connector) {
   List<UpdateWorkerTask> tasks =
       JPAUtils.find(
           em,
           UpdateWorkerTask.class,
           "updateWorkerTasks.isInProgressOrScheduledBefore",
           System.currentTimeMillis(),
           guestId,
           connector.getName());
   HashMap<Integer, UpdateWorkerTask> seen = new HashMap<Integer, UpdateWorkerTask>();
   for (UpdateWorkerTask task : tasks) {
     if (hasStalled(task)) {
       task.status = Status.STALLED;
       em.merge(task);
     } else {
       if (seen.containsKey(task.objectTypes)) {
         if (seen.get(task.objectTypes).timeScheduled < task.timeScheduled)
           seen.put(task.objectTypes, task);
       } else {
         seen.put(task.objectTypes, task);
       }
     }
   }
   return seen.values();
 }
 @Transactional(readOnly = false)
 @Override
 public ScheduleResult reScheduleUpdateTask(
     UpdateWorkerTask updt,
     long time,
     boolean incrementRetries,
     UpdateWorkerTask.AuditTrailEntry auditTrailEntry) {
   if (isShuttingDown) {
     StringBuilder sb =
         new StringBuilder(
                 "module=updateQueue component=updateAllConnectors" + " action=updateConnector")
             .append(" message=\"Service is shutting down... Refusing updates\"");
     logger.warn(sb.toString());
     return new ScheduleResult(
         updt.connectorName,
         updt.getObjectTypes(),
         ScheduleResult.ResultType.SYSTEM_IS_SHUTTING_DOWN,
         time);
   }
   if (!incrementRetries) {
     UpdateWorkerTask failed = new UpdateWorkerTask(updt);
     failed.retries = updt.retries;
     failed.connectorName = updt.connectorName;
     failed.status = Status.FAILED;
     failed.guestId = updt.guestId;
     failed.timeScheduled = updt.timeScheduled;
     em.persist(failed);
     updt.retries = 0;
   } else updt.retries += 1;
   updt.addAuditTrailEntry(auditTrailEntry);
   updt.status = Status.SCHEDULED;
   updt.timeScheduled = time;
   em.merge(updt);
   return new ScheduleResult(
       updt.connectorName,
       updt.getObjectTypes(),
       ScheduleResult.ResultType.SCHEDULED_UPDATE_DEFERRED,
       time);
 }
 @Override
 @Transactional(readOnly = false)
 public void setUpdateWorkerTaskStatus(long updateWorkerTaskId, Status status)
     throws RuntimeException {
   UpdateWorkerTask updt = em.find(UpdateWorkerTask.class, updateWorkerTaskId);
   if (updt == null) {
     RuntimeException exception =
         new RuntimeException(
             "null UpdateWorkerTask trying to set its status: " + updateWorkerTaskId);
     logger.error(
         "module=updateQueue component=connectorUpdateService action=setUpdateWorkerTaskStatus");
     throw exception;
   }
   updt.status = status;
 }
 @Override
 @Transactional(readOnly = false)
 public List<UpdateWorkerTask> getScheduledOrInProgressUpdateTasks(
     long guestId, Connector connector) {
   List<UpdateWorkerTask> updateWorkerTask =
       JPAUtils.find(
           em,
           UpdateWorkerTask.class,
           "updateWorkerTasks.isScheduledOrInProgress",
           guestId,
           connector.getName());
   for (UpdateWorkerTask workerTask : updateWorkerTask) {
     if (hasStalled(workerTask)) {
       workerTask.status = Status.STALLED;
       em.merge(workerTask);
     }
   }
   return updateWorkerTask;
 }
 @Override
 @Transactional(readOnly = false)
 public UpdateWorkerTask getScheduledUpdateTask(
     long guestId, String connectorName, int objectTypes) {
   UpdateWorkerTask updateWorkerTask =
       JPAUtils.findUnique(
           em,
           UpdateWorkerTask.class,
           "updateWorkerTasks.withObjectTypes.isScheduled",
           Status.SCHEDULED,
           Status.IN_PROGRESS,
           guestId,
           objectTypes,
           connectorName);
   if (updateWorkerTask != null && hasStalled(updateWorkerTask)) {
     updateWorkerTask.status = Status.STALLED;
     em.merge(updateWorkerTask);
     return null;
   }
   return updateWorkerTask;
 }
 @Override
 @Transactional(readOnly = false)
 public ScheduleResult scheduleUpdate(
     long guestId,
     String connectorName,
     int objectTypes,
     UpdateType updateType,
     long timeScheduled,
     String... jsonParams) {
   if (isShuttingDown) {
     StringBuilder sb =
         new StringBuilder(
                 "module=updateQueue component=updateAllConnectors" + " action=scheduleUpdate")
             .append(" message=\"Service is shutting down... Refusing updates\"");
     logger.warn(sb.toString());
     return new ScheduleResult(
         connectorName,
         objectTypes,
         ScheduleResult.ResultType.SYSTEM_IS_SHUTTING_DOWN,
         System.currentTimeMillis());
   }
   UpdateWorkerTask updateScheduled = getScheduledUpdateTask(guestId, connectorName, objectTypes);
   ScheduleResult scheduleResult = null;
   if (updateScheduled == null) {
     UpdateWorkerTask updateWorkerTask = new UpdateWorkerTask();
     updateWorkerTask.guestId = guestId;
     updateWorkerTask.connectorName = connectorName;
     updateWorkerTask.objectTypes = objectTypes;
     updateWorkerTask.updateType = updateType;
     updateWorkerTask.status = Status.SCHEDULED;
     updateWorkerTask.timeScheduled = timeScheduled;
     if (jsonParams != null && jsonParams.length > 0) updateWorkerTask.jsonParams = jsonParams[0];
     em.persist(updateWorkerTask);
     long now = System.currentTimeMillis();
     scheduleResult =
         new ScheduleResult(
             connectorName,
             objectTypes,
             timeScheduled <= now
                 ? ScheduleResult.ResultType.SCHEDULED_UPDATE_IMMEDIATE
                 : ScheduleResult.ResultType.SCHEDULED_UPDATE_DEFERRED,
             timeScheduled);
   } else {
     scheduleResult =
         new ScheduleResult(
             connectorName,
             objectTypes,
             ScheduleResult.ResultType.ALREADY_SCHEDULED,
             updateScheduled.timeScheduled);
   }
   StringBuilder sb =
       new StringBuilder(
               "module=updateQueue component=connectorUpdateService action=scheduleUpdate")
           .append(" guestId=")
           .append(guestId)
           .append(" connectorName=")
           .append(connectorName)
           .append(" objectTypes=")
           .append(objectTypes)
           .append(" resultType=")
           .append(scheduleResult.type.toString());
   logger.info(sb.toString());
   return scheduleResult;
 }