@Override
  public void process(JCas aJCas) throws AnalysisEngineProcessException {

    // Keeping track of the ranges of different relation candidates so we wont have duplicate
    // text snippets for different candidates on the same text
    Map<IndexRange, IndexRange> rangeMappings = new HashMap<IndexRange, IndexRange>();

    if (aggregateJCas == null) aggregateJCas = getEmptyJCas();

    CasCopier copier = new CasCopier(aJCas.getCas(), aggregateJCas.getCas());
    Iterator<RelationCandidate> iter = JCasUtil.iterator(aJCas, RelationCandidate.class);

    while (iter.hasNext()) {

      RelationCandidate candidate = iter.next();
      RelationCandidate candidateCopy = (RelationCandidate) copier.copyFs(candidate);

      // See if we already have this candidate in the aggregate jcas
      IndexRange candidateRange = new IndexRange(candidate);
      // The offset between the old jcas and the new of this relation candidate
      int offset = 0;

      if (rangeMappings.containsKey(candidateRange)) {
        offset = rangeMappings.get(candidateRange).getStart() - candidateRange.getStart();
        updateAnnotation(candidateCopy, offset);
        // No need to copy features, has already been done

      } else {
        offset = content.length() - candidateRange.getStart();
        updateAnnotation(candidateCopy, offset);
        rangeMappings.put(candidateRange, new IndexRange(candidateCopy));

        // For every feature we want to copy
        for (Class<? extends Annotation> feature : features) {

          // Iterating over the annotations of this feature type covered by this relation candidate
          for (Annotation annotation : JCasUtil.selectCovered(aJCas, feature, candidate)) {
            Annotation cAnnotation = (Annotation) copier.copyFs(annotation);
            // Updating the indices of the annotation
            updateAnnotation(cAnnotation, offset);
            aggregateJCas.addFsToIndexes(cAnnotation);
          }
        }
        // Adding the text content of the relation candidate to the new cas
        content.append(candidate.getCoveredText());
      }
      aggregateJCas.addFsToIndexes(candidateCopy);
    }
  }