package org.ovirt.engine.core.bll.job; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.job.Job; import org.ovirt.engine.core.common.job.JobExecutionStatus; import org.ovirt.engine.core.common.job.Step; import org.ovirt.engine.core.common.job.StepSubjectEntity; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.JobDao; import org.ovirt.engine.core.dao.JobSubjectEntityDao; import org.ovirt.engine.core.dao.StepDao; import org.ovirt.engine.core.dao.StepSubjectEntityDao; import org.ovirt.engine.core.utils.collections.MultiValueMapUtils; import org.ovirt.engine.core.utils.transaction.TransactionSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implements the CRUD operations for the Job entities. */ @Singleton public class JobRepositoryImpl implements JobRepository { private static final Logger log = LoggerFactory.getLogger(JobRepositoryImpl.class); private final JobDao jobDao; private final JobSubjectEntityDao jobSubjectEntityDao; private final StepDao stepDao; private final StepSubjectEntityDao stepSubjectEntityDao; @Inject public JobRepositoryImpl(JobDao jobDao, JobSubjectEntityDao jobSubjectEntityDao, StepDao stepDao, StepSubjectEntityDao stepSubjectEntityDao) { this.jobDao = jobDao; this.jobSubjectEntityDao = jobSubjectEntityDao; this.stepDao = stepDao; this.stepSubjectEntityDao = stepSubjectEntityDao; } @Override public void saveStep(final Step step) { saveStep(step, Collections.emptyList()); } @Override public void saveStep(final Step step, Collection<StepSubjectEntity> stepSubjectEntities) { stepSubjectEntities.forEach(x -> x.setStepId(step.getId())); TransactionSupport.executeInNewTransaction(() -> { try { jobDao.updateJobLastUpdateTime(step.getJobId(), new Date()); stepDao.save(step); stepSubjectEntityDao.saveAll(stepSubjectEntities); } catch (Exception e) { log.error("Failed to save step '{}', '{}': {}", step.getId(), step.getStepName(), e.getMessage()); log.debug("Exception", e); } return null; }); } @Override public void updateStep(final Step step) { TransactionSupport.executeInNewTransaction(() -> { try { jobDao.updateJobLastUpdateTime(step.getJobId(), new Date()); stepDao.update(step); } catch (Exception e) { log.error("Failed to update step '{}', '{}': {}", step.getId(), step.getStepName(), e.getMessage()); log.debug("Exception", e); } return null; }); } @Override public void saveJob(final Job job) { TransactionSupport.executeInNewTransaction(() -> { jobDao.save(job); Set<Entry<Guid, VdcObjectType>> entrySet = job.getJobSubjectEntities().entrySet(); for (Entry<Guid, VdcObjectType> entry : entrySet) { jobSubjectEntityDao.save(job.getId(), entry.getKey(), entry.getValue()); } return null; }); } @Override public Job getJob(final Guid jobId) { Job job = jobDao.get(jobId); if (job != null) { Map<Guid, VdcObjectType> jobSubjectEntity = jobSubjectEntityDao.getJobSubjectEntityByJobId(jobId); job.setJobSubjectEntities(jobSubjectEntity); } return job; } @Override public Job getJobWithSteps(final Guid jobId) { Job job = jobDao.get(jobId); if (job != null) { Map<Guid, VdcObjectType> jobSubjectEntity = jobSubjectEntityDao.getJobSubjectEntityByJobId(jobId); job.setJobSubjectEntities(jobSubjectEntity); loadJobSteps(job); } return job; } @Override public void loadJobSteps(final Job job) { List<Step> steps = stepDao.getStepsByJobId(job.getId()); if (!steps.isEmpty()) { job.setSteps(buildStepsTree(steps)); } } @Override public void loadParentStepSteps(final Step step) { List<Step> steps = stepDao.getStepsByParentStepId(step.getId()); if (!steps.isEmpty()) { step.setSteps(steps); } } /** * Gets a list of {@link Step} entities ordered by: * <li> parent step id, preceded by nulls * <li> step number * @return a collection of the steps. */ private List<Step> buildStepsTree(List<Step> steps) { List<Step> jobDirectSteps = new ArrayList<>(); // a map of parent step id and a list of child-steps Map<Guid, List<Step>> parentStepMap = new HashMap<>(); for (Step step : steps) { if (step.getParentStepId() == null) { jobDirectSteps.add(step); } else { MultiValueMapUtils.addToMap(step.getParentStepId(), step, parentStepMap); } } for (Step step : steps) { if (parentStepMap.containsKey(step.getId())) { step.setSteps(parentStepMap.get(step.getId())); } } return jobDirectSteps; } @Override public Step getStep(Guid stepId, boolean loadSubjectEntities) { Step step = stepDao.get(stepId); if (step != null && loadSubjectEntities) { step.setSubjectEntities(stepSubjectEntityDao.getStepSubjectEntitiesByStepId(stepId)); } return step; } @Override public List<Job> getJobsByEntityAndAction(Guid entityId, VdcActionType actionType) { List<Job> jobList = new ArrayList<>(); List<Guid> jobIdsList = jobSubjectEntityDao.getJobIdByEntityId(entityId); for (Guid jobId : jobIdsList) { Job job = jobDao.get(jobId); if (job != null && job.getActionType() == actionType) { jobList.add(job); } } return jobList; } @Override public void updateExistingStepAndSaveNewStep(final Step existingStep, final Step newStep) { TransactionSupport.executeInNewTransaction(() -> { jobDao.updateJobLastUpdateTime(existingStep.getJobId(), new Date()); stepDao.update(existingStep); stepDao.save(newStep); return null; }); } @Override public void updateCompletedJobAndSteps(final Job job) { TransactionSupport.executeInNewTransaction(() -> { jobDao.update(job); stepDao.updateJobStepsCompleted(job.getId(), job.getStatus(), job.getEndTime()); return null; }); } @Override public void closeCompletedJobSteps(final Guid jobId, final JobExecutionStatus status) { TransactionSupport.executeInNewTransaction(() -> { stepDao.updateJobStepsCompleted(jobId, status, new Date()); return null; }); } @Override public void finalizeJobs() { TransactionSupport.executeInNewTransaction(() -> { jobDao.deleteRunningJobsOfTasklessCommands(); jobDao.updateStartedExecutionEntitiesToUnknown(new Date()); return null; }); } }