/**
  * Retrieves all Proteins, cross references and matches for a range
  *
  * @param bottom range lower bound (included)
  * @param top range upper bound (included)
  * @return The Protein, with matches loaded. (matches are LAZY by default) or null if the primary
  *     key is not present in the database.
  */
 @Override
 @Transactional(readOnly = true)
 @SuppressWarnings("unchecked")
 public List<Protein> getProteinsAndMatchesAndCrossReferencesBetweenIds(long bottom, long top) {
   Query query =
       entityManager.createQuery(
           "select distinct p from Protein p "
               + "left outer join fetch p.matches "
               + "left outer join fetch p.crossReferences where p.id >= :bottom and p.id <= :top");
   query.setParameter("bottom", bottom);
   query.setParameter("top", top);
   List<Protein> matchingProteins = (List<Protein>) query.getResultList();
   if (LOGGER.isTraceEnabled()) {
     LOGGER.trace("Querying proteins with IDs in range: " + bottom + " to " + top);
     LOGGER.trace("Matching protein count: " + matchingProteins.size());
     for (Protein protein : matchingProteins) {
       LOGGER.trace("Protein ID: " + protein.getId() + " MD5: " + protein.getMd5());
       LOGGER.trace("Has " + protein.getMatches().size() + " matches");
       for (ProteinXref xref : protein.getCrossReferences()) {
         LOGGER.trace("Xref: " + xref.getIdentifier());
       }
     }
   }
   return matchingProteins;
 }
  /**
   * Writes out all protein matches for the specified protein (GFF formatted).
   *
   * @param protein containing matches to be written out
   * @return the number of rows printed (i.e. the number of Locations on Matches).
   * @throws java.io.IOException in the event of I/O problem writing out the file.
   */
  public int write(Protein protein) throws IOException {
    List<String> proteinIdsForGFF = getProteinAccessions(protein);

    int sequenceLength = protein.getSequenceLength();
    String md5 = protein.getMd5();
    String date = dmyFormat.format(new Date());
    Set<Match> matches = protein.getMatches();
    // Write sequence region information
    for (String proteinIdForGFF : proteinIdsForGFF) {
      if (matches.size() > 0) {
        // Check if protein accessions are GFF3 valid
        proteinIdForGFF = ProteinMatchesGFFResultWriter.getValidGFF3SeqId(proteinIdForGFF);
        // Write sequence-region
        super.gffWriter.write("##sequence-region " + proteinIdForGFF + " 1 " + sequenceLength);
        if (writeFullGFF) {
          writeReferenceLine(proteinIdForGFF, sequenceLength, md5);
          addFASTASeqToMap(proteinIdForGFF, protein.getSequence());
        }
        processMatches(matches, proteinIdForGFF, date, protein, proteinIdForGFF, writeFullGFF);
      } // end match size check
    }
    return 0;
  }