/**
  * Returns the assigned ticket ids.
  *
  * @return the assigned ticket ids
  */
 @Override
 public synchronized Set<Long> getIds(RepositoryModel repository) {
   Repository db = repositoryManager.getRepository(repository.name);
   try {
     if (getTicketsBranch(db) == null) {
       return Collections.emptySet();
     }
     Set<Long> ids = new TreeSet<Long>();
     List<PathModel> paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH);
     for (PathModel path : paths) {
       String name = path.name.substring(path.name.lastIndexOf('/') + 1);
       if (!JOURNAL.equals(name)) {
         continue;
       }
       String tid = path.path.split("/")[2];
       long ticketId = Long.parseLong(tid);
       ids.add(ticketId);
     }
     return ids;
   } finally {
     if (db != null) {
       db.close();
     }
   }
 }
  /**
   * Returns all the tickets in the repository. Querying tickets from the repository requires
   * deserializing all tickets. This is an expensive process and not recommended. Tickets are
   * indexed by Lucene and queries should be executed against that index.
   *
   * @param repository
   * @param filter optional filter to only return matching results
   * @return a list of tickets
   */
  @Override
  public List<TicketModel> getTickets(RepositoryModel repository, TicketFilter filter) {
    List<TicketModel> list = new ArrayList<TicketModel>();

    Repository db = repositoryManager.getRepository(repository.name);
    try {
      RefModel ticketsBranch = getTicketsBranch(db);
      if (ticketsBranch == null) {
        return list;
      }

      // Collect the set of all json files
      List<PathModel> paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH);

      // Deserialize each ticket and optionally filter out unwanted tickets
      for (PathModel path : paths) {
        String name = path.name.substring(path.name.lastIndexOf('/') + 1);
        if (!JOURNAL.equals(name)) {
          continue;
        }
        String json = readTicketsFile(db, path.path);
        if (StringUtils.isEmpty(json)) {
          // journal was touched but no changes were written
          continue;
        }
        try {
          // Reconstruct ticketId from the path
          // id/26/326/journal.json
          String tid = path.path.split("/")[2];
          long ticketId = Long.parseLong(tid);
          List<Change> changes = TicketSerializer.deserializeJournal(json);
          if (ArrayUtils.isEmpty(changes)) {
            log.warn("Empty journal for {}:{}", repository, path.path);
            continue;
          }
          TicketModel ticket = TicketModel.buildTicket(changes);
          ticket.project = repository.projectPath;
          ticket.repository = repository.name;
          ticket.number = ticketId;

          // add the ticket, conditionally, to the list
          if (filter == null) {
            list.add(ticket);
          } else {
            if (filter.accept(ticket)) {
              list.add(ticket);
            }
          }
        } catch (Exception e) {
          log.error(
              "failed to deserialize {}/{}\n{}",
              new Object[] {repository, path.path, e.getMessage()});
          log.error(null, e);
        }
      }

      // sort the tickets by creation
      Collections.sort(list);
      return list;
    } finally {
      db.close();
    }
  }