package org.openstack.atlas.service.domain.repository; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openstack.atlas.service.domain.entities.*; import org.openstack.atlas.service.domain.exceptions.EntityNotFoundException; import org.openstack.atlas.service.domain.util.Constants; import org.springframework.stereotype.*; import org.springframework.transaction.annotation.Transactional; import javax.persistence.*; import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @org.springframework.stereotype.Repository @Transactional public class JobStateRepository { final Log LOG = LogFactory.getLog(JobStateRepository.class); @PersistenceContext(unitName = "loadbalancing") private EntityManager entityManager; public JobState getById(Integer id) throws EntityNotFoundException { JobState jobState = entityManager.find(JobState.class, id); if (jobState == null) logAndThrowException(); return jobState; } public List<JobState> getAll(Integer offset, Integer limit, Integer marker) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<JobState> criteria = builder.createQuery(JobState.class); Root<JobState> jobStateRoot = criteria.from(JobState.class); int markerToOffset = 0; if (marker != null) { CriteriaQuery<Integer> criteriaQuery = builder.createQuery(Integer.class); jobStateRoot = criteriaQuery.from(JobState.class); criteriaQuery.select(jobStateRoot.get(JobState_.id)); List<Integer> ids = entityManager.createQuery(criteriaQuery).getResultList(); for (Integer id : ids) { if (id.equals(marker)) { break; } markerToOffset++; } offset = markerToOffset; } if (offset == null) { offset = 0; } if (limit == null || limit > 100 || limit == 0) { limit = 100; } criteria.select(jobStateRoot); TypedQuery<JobState> query = entityManager.createQuery(criteria); query = query.setFirstResult(offset).setMaxResults(limit); return query.getResultList(); } public List<JobState> getByState(String state, Integer... p) { final JobStateVal jobStateVal; try { jobStateVal = JobStateVal.valueOf(state); } catch(IllegalArgumentException e) { return new ArrayList<JobState>(); } CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<JobState> criteria = builder.createQuery(JobState.class); Root<JobState> jobStateRoot = criteria.from(JobState.class); Predicate hasState = builder.equal(jobStateRoot.get(JobState_.state), jobStateVal); criteria.select(jobStateRoot); criteria.where(hasState); TypedQuery<JobState> query = entityManager.createQuery(criteria); if (p.length >= 2) { Integer offset = p[0]; Integer limit = p[1]; if (offset == null) offset = 0; if (limit == null || limit > 100) limit = 100; query = query.setFirstResult(offset).setMaxResults(limit); } return query.getResultList(); } // returns true if a row has THE_ONE_TO_RULE_THEM_ALL on GO // also returns true if THE_ONE_TO_RULE_THEM_ALL doesn't exist (Legacy support) // In case of multiple rows just return true if any are set to GO. public boolean isJobReadyToGo() { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<JobState> criteria = builder.createQuery(JobState.class); Root<JobState> jobStateRoot = criteria.from(JobState.class); Predicate hasName = builder.equal(jobStateRoot.get(JobState_.jobName), JobName.THE_ONE_TO_RULE_THEM_ALL); criteria.select(jobStateRoot); criteria.where(hasName); List<JobState> masterJobs = entityManager.createQuery(criteria).getResultList(); for (JobState masterJobState : masterJobs) { // serieously though there should only be one. if (masterJobState.getState().equals(JobStateVal.GO)) { return true; } } return false; } public JobState getByName(JobName jobName) throws EntityNotFoundException { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<JobState> criteria = builder.createQuery(JobState.class); Root<JobState> jobStateRoot = criteria.from(JobState.class); Predicate hasName = builder.equal(jobStateRoot.get(JobState_.jobName), jobName); criteria.select(jobStateRoot); criteria.where(hasName); try { List<JobState> results = entityManager.createQuery(criteria).getResultList(); if (results.isEmpty()){ throw new NoResultException(); } return results.get(0); } catch (NoResultException e) { logAndThrowException(); } return null; } public List<JobState> getEntriesLike(JobName jobName, String inputPath) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<JobState> criteria = builder.createQuery(JobState.class); Root<JobState> jobStateRoot = criteria.from(JobState.class); Predicate hasName = builder.equal(jobStateRoot.get(JobState_.jobName), jobName); Predicate likeInputPath = builder.like(jobStateRoot.get(JobState_.inputPath), inputPath); Order startTimeOrder = builder.asc(jobStateRoot.get(JobState_.startTime)); criteria.select(jobStateRoot); criteria.where(builder.and(hasName, likeInputPath)); criteria.orderBy(startTimeOrder); return entityManager.createQuery(criteria).getResultList(); } public JobState create(JobName jobName) { return create(jobName, null); } public JobState create(JobName jobName, String inputPath) { JobState s = new JobState(); s.setState(JobStateVal.CREATED); s.setJobName(jobName); s.setInputPath(inputPath); s.setStartTime(Calendar.getInstance()); entityManager.persist(s); return s; } public void update(JobState jobState) { entityManager.merge(jobState); } public void delete(JobState jobState) { entityManager.remove(jobState); } public void deleteByNamesOlderThanNDays(List<JobName> jobNames, int days) { Calendar timestamp = Calendar.getInstance(); timestamp.add(Calendar.DATE, -days); Query query = entityManager.createQuery("DELETE JobState s WHERE s.endTime < :timestamp AND s.jobName IN (:jobNames)") .setParameter("timestamp", timestamp, TemporalType.TIMESTAMP) .setParameter("jobNames", jobNames); int numRowsDeleted = query.executeUpdate(); LOG.info(String.format("Deleted %d rows with endTime before %s", numRowsDeleted, timestamp.getTime())); } private JobState logAndThrowException() throws EntityNotFoundException { String message = Constants.JobNotFound; LOG.debug(message); throw new EntityNotFoundException(message); } }