private TermMentionWithGraphVertex findTermMentionWithGraphVertex(
     List<TermMentionWithGraphVertex> termMentionsWithGraphVertices, TermMention termMention) {
   for (TermMentionWithGraphVertex termMentionsWithGraphVertex : termMentionsWithGraphVertices) {
     if (termMentionsWithGraphVertex.getTermMention().getRowKey().getStartOffset()
             == termMention.getStart()
         && termMentionsWithGraphVertex.getTermMention().getRowKey().getEndOffset()
             == termMention.getEnd()
         && termMentionsWithGraphVertex.getVertex() != null) {
       return termMentionsWithGraphVertex;
     }
   }
   return null;
 }
  private TermMentionWithGraphVertex saveTermMention(
      Vertex artifactGraphVertex,
      TermMention termMention,
      String workspaceId,
      String visibilitySource) {
    LOGGER.debug(
        "Saving term mention '%s':%s:%s (%d:%d)",
        termMention.getSign(),
        termMention.getOntologyClassUri(),
        termMention.getPropertyKey(),
        termMention.getStart(),
        termMention.getEnd());
    Vertex vertex = null;
    if (visibilitySource == null) {
      visibilitySource = termMention.getVisibility().getVisibilityString();
    }

    JSONObject visibilityJson = new JSONObject();
    visibilityJson.put(VisibilityTranslator.JSON_SOURCE, visibilitySource);
    Visibility visibility = visibilityTranslator.toVisibility(visibilityJson).getVisibility();

    Visibility visibilityWithWorkspaceId;
    JSONObject visibilityJsonWithWorkspaceId;
    if (!workspaceId.equals("")) {
      visibilityJsonWithWorkspaceId =
          GraphUtil.updateVisibilitySourceAndAddWorkspaceId(null, visibilitySource, workspaceId);
      visibilityWithWorkspaceId =
          visibilityTranslator.toVisibility(visibilityJsonWithWorkspaceId).getVisibility();
    } else {
      visibilityWithWorkspaceId = visibility;
      visibilityJsonWithWorkspaceId = visibilityJson;
    }

    TermMentionRowKey termMentionRowKey =
        new TermMentionRowKey(
            artifactGraphVertex.getId().toString(),
            termMention.getPropertyKey(),
            termMention.getStart(),
            termMention.getEnd());
    TermMentionModel termMentionModel = new TermMentionModel(termMentionRowKey);
    termMentionModel.getMetadata().setSign(termMention.getSign(), visibility);
    termMentionModel
        .getMetadata()
        .setOntologyClassUri(termMention.getOntologyClassUri(), visibility);
    if (termMention.getProcess() != null && !termMention.getProcess().equals("")) {
      termMentionModel.getMetadata().setAnalyticProcess(termMention.getProcess(), visibility);
    }

    Concept concept = ontologyRepository.getConceptByIRI(termMention.getOntologyClassUri());
    if (concept == null) {
      LOGGER.error("Could not find ontology graph vertex '%s'", termMention.getOntologyClassUri());
      return null;
    }
    termMentionModel.getMetadata().setConceptGraphVertexId(concept.getTitle(), visibility);

    if (termMention.isResolved()) {
      String title = termMention.getSign();
      ElementMutation<Vertex> vertexElementMutation;
      if (termMention.getUseExisting()) {
        graph.flush(); // make sure the previous term mentions have made it into the graph
        if (termMention.getId() != null) {
          vertex = graph.getVertex(termMention.getId(), getAuthorizations());
        } else {
          vertex =
              singleOrDefault(
                  graph
                      .query(getAuthorizations())
                      .has(LumifyProperties.TITLE.getPropertyName(), title)
                      .has(LumifyProperties.CONCEPT_TYPE.getPropertyName(), concept.getTitle())
                      .vertices(),
                  null);
        }
      }

      Map<String, Object> metadata = new HashMap<String, Object>();
      LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setMetadata(
          metadata, visibilityJsonWithWorkspaceId);

      if (vertex == null) {
        if (termMention.getId() != null) {
          vertexElementMutation =
              graph.prepareVertex(termMention.getId(), visibilityWithWorkspaceId);
        } else {
          vertexElementMutation = graph.prepareVertex(visibilityWithWorkspaceId);
        }
        LumifyProperties.TITLE.setProperty(
            vertexElementMutation, title, metadata, visibilityWithWorkspaceId);
        LumifyProperties.CONCEPT_TYPE.setProperty(
            vertexElementMutation, concept.getTitle(), metadata, visibilityWithWorkspaceId);
      } else {
        vertexElementMutation = vertex.prepareMutation();
      }

      for (TermMention.TermMentionProperty termMentionProperty : termMention.getNewProperties()) {
        vertexElementMutation.addPropertyValue(
            termMentionProperty.getKey(),
            termMentionProperty.getName(),
            termMentionProperty.getValue(),
            metadata,
            visibilityWithWorkspaceId);
      }

      LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setProperty(
          vertexElementMutation,
          visibilityJsonWithWorkspaceId,
          metadata,
          visibilityWithWorkspaceId);
      vertexElementMutation.addPropertyValue(
          graph.getIdGenerator().nextId(),
          LumifyProperties.ROW_KEY.getPropertyName(),
          termMentionRowKey.toString(),
          metadata,
          visibilityWithWorkspaceId);

      if (!(vertexElementMutation instanceof ExistingElementMutation)) {
        vertex = vertexElementMutation.save(getAuthorizations());
        auditRepository.auditVertexElementMutation(
            AuditAction.UPDATE,
            vertexElementMutation,
            vertex,
            termMention.getProcess(),
            getUser(),
            visibilityWithWorkspaceId);
      } else {
        auditRepository.auditVertexElementMutation(
            AuditAction.UPDATE,
            vertexElementMutation,
            vertex,
            termMention.getProcess(),
            getUser(),
            visibilityWithWorkspaceId);
        vertex = vertexElementMutation.save(getAuthorizations());
      }

      // TODO: a better way to check if the same edge exists instead of looking it up every time?
      Edge edge =
          singleOrDefault(
              artifactGraphVertex.getEdges(
                  vertex, Direction.OUT, artifactHasEntityIri, getAuthorizations()),
              null);
      if (edge == null) {
        edge =
            graph.addEdge(
                artifactGraphVertex, vertex, artifactHasEntityIri, visibility, getAuthorizations());
        LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setProperty(
            edge,
            visibilityJsonWithWorkspaceId,
            metadata,
            visibilityWithWorkspaceId,
            getAuthorizations());
        auditRepository.auditRelationship(
            AuditAction.CREATE,
            artifactGraphVertex,
            vertex,
            edge,
            termMention.getProcess(),
            "",
            getUser(),
            visibilityWithWorkspaceId);
      }

      graph.flush();
      if (workspaceId != null && !workspaceId.equals("")) {
        Workspace workspace = workspaceRepository.findById(workspaceId, getUser());
        workspaceRepository.updateEntityOnWorkspace(
            workspace, vertex.getId(), null, null, null, getUser());
      }

      termMentionModel
          .getMetadata()
          .setVertexId(vertex.getId().toString(), visibility)
          .setEdgeId(edge.getId().toString(), visibility);
    }

    getTermMentionRepository().save(termMentionModel, FlushFlag.NO_FLUSH);
    return new TermMentionWithGraphVertex(termMentionModel, vertex);
  }