@Clusterable(onMaster = true)
  @Override
  public void cleanUpBackgroundTasks() throws SystemException {
    List<BackgroundTask> backgroundTasks =
        backgroundTaskPersistence.findByStatus(BackgroundTaskConstants.STATUS_IN_PROGRESS);

    for (BackgroundTask backgroundTask : backgroundTasks) {
      backgroundTask.setStatus(BackgroundTaskConstants.STATUS_FAILED);

      cleanUpBackgroundTask(backgroundTask, BackgroundTaskConstants.STATUS_FAILED);
    }
  }
  /**
   * Adds the background task to the database. Also notifies the appropriate model listeners.
   *
   * @param backgroundTask the background task
   * @return the background task that was added
   * @throws SystemException if a system exception occurred
   */
  @Indexable(type = IndexableType.REINDEX)
  @Override
  public BackgroundTask addBackgroundTask(BackgroundTask backgroundTask) throws SystemException {
    backgroundTask.setNew(true);

    return backgroundTaskPersistence.update(backgroundTask);
  }
  @Override
  public BackgroundTask deleteBackgroundTask(BackgroundTask backgroundTask)
      throws PortalException, SystemException {

    long folderId = backgroundTask.getAttachmentsFolderId();

    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
      PortletFileRepositoryUtil.deleteFolder(folderId);
    }

    if (backgroundTask.getStatus() == BackgroundTaskConstants.STATUS_IN_PROGRESS) {

      cleanUpBackgroundTask(backgroundTask, BackgroundTaskConstants.STATUS_CANCELLED);
    }

    return backgroundTaskPersistence.remove(backgroundTask);
  }
  @Clusterable(onMaster = true)
  @Override
  public void resumeBackgroundTask(long backgroundTaskId) throws SystemException {

    BackgroundTask backgroundTask = backgroundTaskPersistence.fetchByPrimaryKey(backgroundTaskId);

    if ((backgroundTask == null)
        || (backgroundTask.getStatus() != BackgroundTaskConstants.STATUS_QUEUED)) {

      return;
    }

    Message message = new Message();

    message.put("backgroundTaskId", backgroundTaskId);

    MessageBusUtil.sendMessage(DestinationNames.BACKGROUND_TASK, message);
  }
  @Override
  public BackgroundTaskResult execute(BackgroundTask backgroundTask) {
    ExportImportConfiguration exportImportConfiguration =
        getExportImportConfiguration(backgroundTask);

    clearBackgroundTaskStatus(backgroundTask);

    MissingReferences missingReferences = null;

    try {
      ExportImportThreadLocal.setLayoutStagingInProcess(true);

      ExportImportLifecycleManager.fireExportImportLifecycleEvent(
          ExportImportLifecycleConstants.EVENT_PUBLICATION_LAYOUT_REMOTE_STARTED,
          exportImportConfiguration);

      missingReferences =
          TransactionHandlerUtil.invoke(
              transactionAttribute,
              new LayoutRemoteStagingCallable(
                  backgroundTask.getBackgroundTaskId(), exportImportConfiguration));

      ExportImportLifecycleManager.fireExportImportLifecycleEvent(
          ExportImportLifecycleConstants.EVENT_PUBLICATION_LAYOUT_REMOTE_SUCCEEDED,
          exportImportConfiguration);
    } catch (Throwable t) {
      ExportImportLifecycleManager.fireExportImportLifecycleEvent(
          ExportImportLifecycleConstants.EVENT_PUBLICATION_LAYOUT_REMOTE_FAILED,
          exportImportConfiguration);

      if (_log.isDebugEnabled()) {
        _log.debug(t, t);
      } else if (_log.isWarnEnabled()) {
        _log.warn("Unable to publish layout: " + t.getMessage());
      }

      throw new SystemException(t);
    } finally {
      ExportImportThreadLocal.setLayoutStagingInProcess(false);
    }

    return processMissingReferences(backgroundTask.getBackgroundTaskId(), missingReferences);
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof BackgroundTask)) {
      return false;
    }

    BackgroundTask backgroundTask = (BackgroundTask) obj;

    long primaryKey = backgroundTask.getPrimaryKey();

    if (getPrimaryKey() == primaryKey) {
      return true;
    } else {
      return false;
    }
  }
  @Override
  public int compareTo(BackgroundTask backgroundTask) {
    int value = 0;

    value = DateUtil.compareTo(getCreateDate(), backgroundTask.getCreateDate());

    if (value != 0) {
      return value;
    }

    return 0;
  }
  @Override
  public void addBackgroundTaskAttachment(
      long userId, long backgroundTaskId, String fileName, InputStream inputStream)
      throws PortalException, SystemException {

    BackgroundTask backgroundTask = getBackgroundTask(backgroundTaskId);

    Folder folder = backgroundTask.addAttachmentsFolder();

    PortletFileRepositoryUtil.addPortletFileEntry(
        backgroundTask.getGroupId(),
        userId,
        BackgroundTask.class.getName(),
        backgroundTask.getPrimaryKey(),
        PortletKeys.BACKGROUND_TASK,
        folder.getFolderId(),
        inputStream,
        fileName,
        ContentTypes.APPLICATION_ZIP,
        false);
  }
  @Clusterable(onMaster = true)
  @Override
  public void cleanUpBackgroundTask(final BackgroundTask backgroundTask, final int status) {

    try {
      Lock lock =
          lockLocalService.getLock(
              BackgroundTaskExecutor.class.getName(), backgroundTask.getTaskExecutorClassName());

      String owner =
          backgroundTask.getName() + StringPool.POUND + backgroundTask.getBackgroundTaskId();

      if (owner.equals(lock.getOwner())) {
        lockLocalService.unlock(
            BackgroundTaskExecutor.class.getName(), backgroundTask.getTaskExecutorClassName());
      }
    } catch (Exception e) {
    }

    TransactionCommitCallbackRegistryUtil.registerCallback(
        new Callable<Void>() {

          @Override
          public Void call() throws Exception {
            Message message = new Message();

            message.put("backgroundTaskId", backgroundTask.getBackgroundTaskId());
            message.put("name", backgroundTask.getName());
            message.put("status", status);
            message.put("taskExecutorClassName", backgroundTask.getTaskExecutorClassName());

            MessageBusUtil.sendMessage(DestinationNames.BACKGROUND_TASK_STATUS, message);

            return null;
          }
        });
  }
  @Override
  public BackgroundTaskResult execute(BackgroundTask backgroundTask) throws PortalException {

    ExportImportConfiguration exportImportConfiguration =
        getExportImportConfiguration(backgroundTask);

    Map<String, Serializable> settingsMap = exportImportConfiguration.getSettingsMap();

    long userId = MapUtil.getLong(settingsMap, "userId");
    long groupId = MapUtil.getLong(settingsMap, "sourceGroupId");
    boolean privateLayout = MapUtil.getBoolean(settingsMap, "privateLayout");
    long[] layoutIds = GetterUtil.getLongValues(settingsMap.get("layoutIds"));
    Map<String, String[]> parameterMap = (Map<String, String[]>) settingsMap.get("parameterMap");
    DateRange dateRange =
        ExportImportDateUtil.getDateRange(
            exportImportConfiguration, ExportImportDateUtil.RANGE_ALL);

    StringBundler sb = new StringBundler(4);

    sb.append(
        StringUtil.replace(
            exportImportConfiguration.getName(), StringPool.SPACE, StringPool.UNDERLINE));
    sb.append(StringPool.DASH);
    sb.append(Time.getShortTimestamp());
    sb.append(".lar");

    File larFile =
        LayoutLocalServiceUtil.exportLayoutsAsFile(
            groupId,
            privateLayout,
            layoutIds,
            parameterMap,
            dateRange.getStartDate(),
            dateRange.getEndDate());

    BackgroundTaskLocalServiceUtil.addBackgroundTaskAttachment(
        userId, backgroundTask.getBackgroundTaskId(), sb.toString(), larFile);

    boolean updateLastPublishDate =
        MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);

    if (updateLastPublishDate) {
      ExportImportDateUtil.updateLastPublishDate(
          groupId, privateLayout, dateRange, dateRange.getEndDate());
    }

    return BackgroundTaskResult.SUCCESS;
  }
  @Override
  public BackgroundTask amendBackgroundTask(
      long backgroundTaskId,
      Map<String, Serializable> taskContextMap,
      int status,
      String statusMessage,
      ServiceContext serviceContext)
      throws SystemException {

    Date now = new Date();

    BackgroundTask backgroundTask = backgroundTaskPersistence.fetchByPrimaryKey(backgroundTaskId);

    if (backgroundTask == null) {
      return null;
    }

    backgroundTask.setModifiedDate(serviceContext.getModifiedDate(now));

    if (taskContextMap != null) {
      String taskContext = JSONFactoryUtil.serialize(taskContextMap);

      backgroundTask.setTaskContext(taskContext);
    }

    if ((status == BackgroundTaskConstants.STATUS_FAILED)
        || (status == BackgroundTaskConstants.STATUS_SUCCESSFUL)) {

      backgroundTask.setCompleted(true);
      backgroundTask.setCompletionDate(now);
    }

    backgroundTask.setStatus(status);

    if (Validator.isNotNull(statusMessage)) {
      backgroundTask.setStatusMessage(statusMessage);
    }

    backgroundTaskPersistence.update(backgroundTask);

    return backgroundTask;
  }
    @Override
    public MissingReferences call() throws PortalException {
      long stagingRequestId = 0;

      File file = null;
      FileInputStream fileInputStream = null;
      HttpPrincipal httpPrincipal = null;
      MissingReferences missingReferences = null;

      try {
        Map<String, Serializable> settingsMap = _exportImportConfiguration.getSettingsMap();

        long sourceGroupId = MapUtil.getLong(settingsMap, "sourceGroupId");
        boolean privateLayout = MapUtil.getBoolean(settingsMap, "privateLayout");

        initThreadLocals(sourceGroupId, privateLayout);

        Map<Long, Boolean> layoutIdMap = (Map<Long, Boolean>) settingsMap.get("layoutIdMap");
        Map<String, String[]> parameterMap =
            (Map<String, String[]>) settingsMap.get("parameterMap");
        long remoteGroupId = MapUtil.getLong(settingsMap, "remoteGroupId");
        DateRange dateRange = ExportImportDateUtil.getDateRange(_exportImportConfiguration);

        BackgroundTask backgroundTask =
            BackgroundTaskLocalServiceUtil.getBackgroundTask(_backgroundTaskId);

        Map<String, Serializable> taskContextMap = backgroundTask.getTaskContextMap();

        httpPrincipal = (HttpPrincipal) taskContextMap.get("httpPrincipal");

        file =
            exportLayoutsAsFile(
                sourceGroupId,
                privateLayout,
                layoutIdMap,
                parameterMap,
                remoteGroupId,
                dateRange.getStartDate(),
                dateRange.getEndDate(),
                httpPrincipal);

        String checksum = FileUtil.getMD5Checksum(file);

        fileInputStream = new FileInputStream(file);

        stagingRequestId =
            StagingServiceHttp.createStagingRequest(httpPrincipal, remoteGroupId, checksum);

        byte[] bytes = new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];

        int i = 0;
        int j = 0;

        String numberFormat =
            String.format(
                "%%0%dd", String.valueOf((int) (file.length() / bytes.length)).length() + 1);

        while ((i = fileInputStream.read(bytes)) >= 0) {
          String fileName = file.getName() + String.format(numberFormat, j++);

          if (i < PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE) {
            byte[] tempBytes = new byte[i];

            System.arraycopy(bytes, 0, tempBytes, 0, i);

            StagingServiceHttp.updateStagingRequest(
                httpPrincipal, stagingRequestId, fileName, tempBytes);
          } else {
            StagingServiceHttp.updateStagingRequest(
                httpPrincipal, stagingRequestId, fileName, bytes);
          }

          bytes = new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];
        }

        markBackgroundTask(_backgroundTaskId, "exported");

        StagingServiceHttp.publishStagingRequest(
            httpPrincipal, stagingRequestId, privateLayout, parameterMap);
      } catch (IOException ioe) {
        deleteTempLarOnFailure(file);

        throw new SystemException(ioe);
      } catch (Throwable t) {
        deleteTempLarOnFailure(file);

        throw t;
      } finally {
        StreamUtil.cleanUp(fileInputStream);

        if (stagingRequestId > 0) {
          StagingServiceHttp.cleanUpStagingRequest(httpPrincipal, stagingRequestId);
        }
      }

      deleteTempLarOnSuccess(file);

      return missingReferences;
    }
  /**
   * Converts the soap model instance into a normal model instance.
   *
   * @param soapModel the soap model instance to convert
   * @return the normal model instance
   */
  public static BackgroundTask toModel(BackgroundTaskSoap soapModel) {
    if (soapModel == null) {
      return null;
    }

    BackgroundTask model = new BackgroundTaskImpl();

    model.setMvccVersion(soapModel.getMvccVersion());
    model.setBackgroundTaskId(soapModel.getBackgroundTaskId());
    model.setGroupId(soapModel.getGroupId());
    model.setCompanyId(soapModel.getCompanyId());
    model.setUserId(soapModel.getUserId());
    model.setUserName(soapModel.getUserName());
    model.setCreateDate(soapModel.getCreateDate());
    model.setModifiedDate(soapModel.getModifiedDate());
    model.setName(soapModel.getName());
    model.setServletContextNames(soapModel.getServletContextNames());
    model.setTaskExecutorClassName(soapModel.getTaskExecutorClassName());
    model.setTaskContext(soapModel.getTaskContext());
    model.setCompleted(soapModel.getCompleted());
    model.setCompletionDate(soapModel.getCompletionDate());
    model.setStatus(soapModel.getStatus());
    model.setStatusMessage(soapModel.getStatusMessage());

    return model;
  }
  @Override
  public BackgroundTask addBackgroundTask(
      long userId,
      long groupId,
      String name,
      String[] servletContextNames,
      Class<?> taskExecutorClass,
      Map<String, Serializable> taskContextMap,
      ServiceContext serviceContext)
      throws PortalException, SystemException {

    User user = userPersistence.findByPrimaryKey(userId);
    Date now = new Date();

    final long backgroundTaskId = counterLocalService.increment();

    BackgroundTask backgroundTask = backgroundTaskPersistence.create(backgroundTaskId);

    backgroundTask.setCompanyId(user.getCompanyId());
    backgroundTask.setCreateDate(serviceContext.getCreateDate(now));
    backgroundTask.setGroupId(groupId);
    backgroundTask.setModifiedDate(serviceContext.getModifiedDate(now));
    backgroundTask.setUserId(userId);
    backgroundTask.setUserName(user.getFullName());
    backgroundTask.setName(name);
    backgroundTask.setServletContextNames(StringUtil.merge(servletContextNames));
    backgroundTask.setTaskExecutorClassName(taskExecutorClass.getName());

    if (taskContextMap != null) {
      String taskContext = JSONFactoryUtil.serialize(taskContextMap);

      backgroundTask.setTaskContext(taskContext);
    }

    backgroundTask.setStatus(BackgroundTaskConstants.STATUS_NEW);

    backgroundTaskPersistence.update(backgroundTask);

    TransactionCommitCallbackRegistryUtil.registerCallback(
        new Callable<Void>() {

          @Override
          public Void call() throws Exception {
            backgroundTaskLocalService.triggerBackgroundTask(backgroundTaskId);

            return null;
          }
        });

    return backgroundTask;
  }