class ActionDBAccessorImpl implements ActionDBAccessor {

  @Override
  @Transactional
  @TransactionalLock(lockArea = LockArea.HRC_STATUS_CACHE, lockType = LockType.WRITE)
  public void persistActions(Request request) throws AmbariException {

    RequestEntity requestEntity = request.constructNewPersistenceEntity();

    Long clusterId = -1L;
    String clusterName = null;
    Long requestId = requestEntity.getRequestId();
    ClusterEntity clusterEntity = clusterDAO.findById(request.getClusterId());
    if (clusterEntity != null) {
      clusterId = clusterEntity.getClusterId();
      clusterName = clusterEntity.getClusterName();
    }

    requestEntity.setClusterId(clusterId);
    requestDAO.create(requestEntity);

    //TODO wire request to cluster
    List<StageEntity> stageEntities = new ArrayList<>(request.getStages().size());

    addRequestToAuditlogCache(request);

    List<HostRoleCommand> hostRoleCommands = new ArrayList<>();

    for (Stage stage : request.getStages()) {
      StageEntity stageEntity = stage.constructNewPersistenceEntity();
      Long stageId = stageEntity.getStageId();
      stageEntities.add(stageEntity);
      stageEntity.setClusterId(clusterId);
      stageEntity.setRequest(requestEntity);
      stageDAO.create(stageEntity);

      List<HostRoleCommand> orderedHostRoleCommands = stage.getOrderedHostRoleCommands();
      List<HostRoleCommandEntity> hostRoleCommandEntities = new ArrayList<>();

      for (HostRoleCommand hostRoleCommand : orderedHostRoleCommands) {
        hostRoleCommand.setRequestId(requestId);
        hostRoleCommand.setStageId(stageId);
        HostRoleCommandEntity hostRoleCommandEntity = hostRoleCommand.constructNewPersistenceEntity();
        hostRoleCommandEntity.setStage(stageEntity);
        hostRoleCommandDAO.create(hostRoleCommandEntity);
        hostRoleCommandEntities.add(hostRoleCommandEntity);

        hostRoleCommand.setTaskId(hostRoleCommandEntity.getTaskId());

        String prefix = "";
        String output = "output-" + hostRoleCommandEntity.getTaskId() + ".txt";
        String error = "errors-" + hostRoleCommandEntity.getTaskId() + ".txt";

        HostEntity hostEntity = null;
        if (null != hostRoleCommandEntity.getHostId()) {
          hostEntity = hostDAO.findById(hostRoleCommandEntity.getHostId());
          if (hostEntity == null) {
            String msg = String.format("Host %s doesn't exist in database", hostRoleCommandEntity.getHostName());
            LOG.error(msg);
            throw new AmbariException(msg);
          }

          hostRoleCommandEntity.setHostEntity(hostEntity);

          try {
            // Get the in-memory host object and its prefix to construct the output and error log paths.
            Host hostObject = clusters.getHost(hostEntity.getHostName());

            if (!StringUtils.isBlank(hostObject.getPrefix())) {
              prefix = hostObject.getPrefix();
              if (!prefix.endsWith("/")) {
                prefix = prefix + "/";
              }
            }
          } catch (AmbariException e) {
            LOG.warn("Exception in getting prefix for host and setting output and error log files.  Using no prefix");
          }
        }

        hostRoleCommand.setOutputLog(prefix + output);
        hostRoleCommand.setErrorLog(prefix + error);
        hostRoleCommandEntity.setOutputLog(hostRoleCommand.getOutputLog());
        hostRoleCommandEntity.setErrorLog(hostRoleCommand.getErrorLog());

        ExecutionCommandEntity executionCommandEntity = hostRoleCommand.constructExecutionCommandEntity();
        executionCommandEntity.setHostRoleCommand(hostRoleCommandEntity);

        executionCommandEntity.setTaskId(hostRoleCommandEntity.getTaskId());
        hostRoleCommandEntity.setExecutionCommand(executionCommandEntity);

        executionCommandDAO.create(hostRoleCommandEntity.getExecutionCommand());
        hostRoleCommandEntity = hostRoleCommandDAO.mergeWithoutPublishEvent(hostRoleCommandEntity);

        if (null != hostEntity) {
          hostEntity = hostDAO.merge(hostEntity);
        }
        hostRoleCommands.add(hostRoleCommand);
      }

      for (RoleSuccessCriteriaEntity roleSuccessCriteriaEntity : stageEntity.getRoleSuccessCriterias()) {
        roleSuccessCriteriaDAO.create(roleSuccessCriteriaEntity);
      }

      stageEntity.setHostRoleCommands(hostRoleCommandEntities);
      stageEntity = stageDAO.merge(stageEntity);
    }

    requestEntity.setStages(stageEntities);
    requestDAO.merge(requestEntity);

    TaskCreateEvent taskCreateEvent = new TaskCreateEvent(hostRoleCommands);
    taskEventPublisher.publish(taskCreateEvent);
    List<HostRoleCommandEntity> hostRoleCommandEntities = hostRoleCommandDAO.findByRequest(requestEntity.getRequestId());

    // "requests" STOMP topic is used for clusters related requests only.
    // Requests without clusters (like host checks) should be posted to divided topic.
    if (clusterName != null) {
      STOMPUpdatePublisher.publish(new RequestUpdateEvent(requestEntity,
          hostRoleCommandDAO, topologyManager, clusterName, hostRoleCommandEntities));
    } else {
      LOG.debug("No STOMP request update event was fired for new request due no cluster related, " +
              "request id: {}, command name: {}",
          requestEntity.getRequestId(),
          requestEntity.getCommandName());
    }
  }

  @Inject public  ActionDBAccessorImpl(@Named("executionCommandCacheSize") long cacheLimit,
                              AmbariEventPublisher eventPublisher);

}