Coverage Summary for Class: TaskDAO (org.kitodo.data.database.persistence)

Class Class, % Method, % Line, %
TaskDAO 100% (1/1) 75% (9/12) 87,8% (43/49)


 /*
  * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
  *
  * This file is part of the Kitodo project.
  *
  * It is licensed under GNU General Public License version 3 or later.
  *
  * For the full copyright and license information, please read the
  * GPL3-License.txt file that was distributed with this source code.
  */
 
 package org.kitodo.data.database.persistence;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
 import javax.persistence.PersistenceException;
 
 import org.hibernate.Session;
 import org.hibernate.query.NativeQuery;
 import org.hibernate.type.StandardBasicTypes;
 import org.kitodo.data.database.beans.Process;
 import org.kitodo.data.database.beans.Task;
 import org.kitodo.data.database.enums.TaskStatus;
 import org.kitodo.data.database.exceptions.DAOException;
 
 public class TaskDAO extends BaseDAO<Task> {
 
     private static final String KEY_PROCESS_ID = "processId";
 
     @Override
     public Task getById(Integer id) throws DAOException {
         Task task = retrieveObject(Task.class, id);
         if (task == null) {
             throw new DAOException("Object cannot be found in database");
         }
         return task;
     }
 
     @Override
     public List<Task> getAll() throws DAOException {
         return retrieveAllObjects(Task.class);
     }
 
     @Override
     public List<Task> getAll(int offset, int size) throws DAOException {
         return retrieveObjects("FROM Task WHERE " + getDateFilter("processingBegin") + " ORDER BY id ASC", offset,
             size);
     }
 
     @Override
     public List<Task> getAllNotIndexed(int offset, int size) throws DAOException {
         return retrieveObjects("FROM Task WHERE " + getDateFilter("processingBegin")
                 + " AND (indexAction = 'INDEX' OR indexAction IS NULL) ORDER BY id ASC",
             offset,
             size);
     }
 
     @Override
     public void remove(Integer id) throws DAOException {
         removeObject(Task.class, id);
     }
 
     public void update(Task task) {
         updateObject(task);
     }
 
     /**
      * Get current tasks with exact title for batch with exact id.
      *
      * @param title
      *            of task as String
      * @param batchId
      *            id of batch as Integer
      * @return list of Task objects
      */
     public List<Task> getCurrentTasksOfBatch(String title, Integer batchId) {
         Map<String, Object> parameters = new HashMap<>();
         parameters.put("title", title);
         parameters.put("batchId", batchId);
         return getByQuery("SELECT t FROM Task AS t INNER JOIN t.process AS p INNER JOIN p.batches AS b WHERE t.title = "
                 + ":title AND batchStep = 1 AND b.id = :batchId",
             parameters);
     }
 
     /**
      * Get all tasks between two given ordering of tasks for given process id.
      *
      * @param orderingMax
      *            as Integer
      * @param orderingMin
      *            as Integer
      * @param processId
      *            id of process for which tasks are searched as Integer
      * @return list of Task objects
      */
     public List<Task> getAllTasksInBetween(Integer orderingMax, Integer orderingMin, Integer processId) {
         Map<String, Object> parameters = new HashMap<>();
         parameters.put("orderingMax", orderingMax);
         parameters.put("orderingMin", orderingMin);
         parameters.put(KEY_PROCESS_ID, processId);
         return getByQuery("FROM Task WHERE process_id = :processId AND ordering < :orderingMin"
                 + " AND ordering > :orderingMax ORDER BY ordering ASC",
             parameters);
     }
 
     /**
      * Get next tasks for problem solution for given process id.
      *
      * @param ordering
      *            of Task for which it searches next ones as Integer
      * @param processId
      *            id of process for which tasks are searched as Integer
      * @return list of Task objects
      */
     public List<Task> getNextTasksForProblemSolution(Integer ordering, Integer processId) {
         Map<String, Object> parameters = new HashMap<>();
         parameters.put("ordering", ordering);
         parameters.put(KEY_PROCESS_ID, processId);
         return getByQuery("FROM Task WHERE process_id = :processId AND ordering > :ordering AND repeatOnCorrection = 1",
             parameters);
     }
 
     /**
      * Get previous tasks for problem solution for given process id.
      *
      * @param ordering
      *            of Task for which it searches previous ones as Integer
      * @param processId
      *            id of process for which tasks are searched as Integer
      * @return list of Task objects
      */
     public List<Task> getPreviousTasksForProblemReporting(Integer ordering, Integer processId) {
         Map<String, Object> parameters = new HashMap<>();
         parameters.put("ordering", ordering);
         parameters.put(KEY_PROCESS_ID, processId);
         return getByQuery(
             "FROM Task WHERE process_id = :processId AND ordering < :ordering" + " ORDER BY ordering DESC", parameters);
     }
 
     /**
      * Counts how many tasks have a certain status for the provided process and all its ancestor processes.
      * 
      * <p>The counts are used to calculate the process progress status</p>
      * 
      * @param process the process to be queried for tasks and their status counts
      * @return a count for each TaskStatus 
      */
     @SuppressWarnings("unchecked")
     public Map<TaskStatus, Integer> countTaskStatusForProcessAndItsAncestors(Process process) throws DAOException {
         if (Objects.isNull(process)) {
             throw new DAOException("can not count task status for process that is null");
         }
         if (Objects.isNull(process.getId())) {
             throw new DAOException("can not count task status for process that has id of null");
         }
         
         // initialize counts
         Map<TaskStatus, Integer> counts = new HashMap<>();
         counts.put(TaskStatus.OPEN, 0);
         counts.put(TaskStatus.INWORK, 0);
         counts.put(TaskStatus.LOCKED, 0);
         counts.put(TaskStatus.DONE, 0);
 
         // perform query and read data
         try (Session session = HibernateUtil.getSession()) {
             // do not use hibernate query language, which does not support recursive queries, use native SQL instead
             // do not use query parameter with recursive query, which works with MySQL and MariaDB but not h2 database
             NativeQuery<Object[]> query = session.createSQLQuery(
                 "SELECT t.processingStatus as status, COUNT(*) as count FROM task t, ("
                     + "    WITH RECURSIVE process_children(id) as ("
                     + "        (SELECT id FROM process WHERE id = " + process.getId() + ")"
                     + "        UNION ALL"
                     + "        (SELECT p1.id from process as p1, process_children as p2 WHERE p2.id = p1.parent_id)"
                     + "    ) SELECT id FROM process_children"
                     + ") as p WHERE t.process_id = p.id GROUP BY t.processingStatus;"
             );
             query.addScalar("status", StandardBasicTypes.INTEGER);
             query.addScalar("count", StandardBasicTypes.INTEGER);
             
             for (Object[] row : query.list()) {
                 TaskStatus status = TaskStatus.getStatusFromValue((int)row[0]);
                 Integer count = (int)row[1];
                 counts.put(status, count);
             }
 
             return counts;
         } catch (PersistenceException e) {
             // catch any exceptions that might be thrown by internals of database connector
             // due to recursive query, which might not be supported by some databases
             throw new DAOException(e);
         }
     }
 }