@Override
  public void handle(HttpServletRequest request, HttpServletResponse response, HandlerChain chain)
      throws Exception {
    LumifyVisibility lumifyVisibility = new LumifyVisibility();
    final String propertyName = getRequiredParameter(request, "propertyName");
    final String propertyKey = getRequiredParameter(request, "propertyKey");
    final String sourceId = getRequiredParameter(request, "source");
    final String destId = getRequiredParameter(request, "dest");
    final String edgeId = getRequiredParameter(request, "edgeId");

    User user = getUser(request);
    Authorizations authorizations = getAuthorizations(request, user);
    String workspaceId = getActiveWorkspaceId(request);

    OntologyProperty property = ontologyRepository.getProperty(propertyName);
    if (property == null) {
      throw new RuntimeException("Could not find property: " + propertyName);
    }

    // TODO remove all properties from all edges? I don't think so
    Edge edge = graph.getEdge(edgeId, authorizations);
    Object oldValue = null;
    Property oldProperty = edge.getProperty(propertyKey, propertyName);
    if (oldProperty != null) {
      oldValue = oldProperty.getValue();
    }
    // TODO: replace "" when we implement commenting on ui
    auditRepository.auditRelationshipProperty(
        AuditAction.DELETE,
        sourceId,
        destId,
        propertyKey,
        property.getDisplayName(),
        oldValue,
        null,
        edge,
        "",
        "",
        user,
        lumifyVisibility.getVisibility());
    edge.removeProperty(propertyKey, propertyName, authorizations);
    graph.flush();

    List<Property> properties = new ArrayList<Property>();
    for (Property p : edge.getProperties()) {
      properties.add(p);
    }

    workQueueRepository.pushGraphPropertyQueue(edge, null, propertyName);

    JSONArray resultsJson = JsonSerializer.toJsonProperties(properties, workspaceId);
    respondWithJson(response, resultsJson);
  }
  @Override
  public void handle(HttpServletRequest request, HttpServletResponse response, HandlerChain chain)
      throws Exception {
    final String artifactId = getRequiredParameter(request, "artifactId");
    final String propertyKey = getRequiredParameter(request, "propertyKey");
    final long mentionStart = getRequiredParameterAsLong(request, "mentionStart");
    final long mentionEnd = getRequiredParameterAsLong(request, "mentionEnd");
    final String title = getRequiredParameter(request, "sign");
    final String conceptId = getRequiredParameter(request, "conceptId");
    final String visibilitySource = getRequiredParameter(request, "visibilitySource");
    final String resolvedVertexId = getOptionalParameter(request, "resolvedVertexId");
    final String justificationText = getOptionalParameter(request, "justificationText");
    final String sourceInfo = getOptionalParameter(request, "sourceInfo");
    String termMentionRowKeyString = getOptionalParameter(request, "rowKey");

    User user = getUser(request);
    String workspaceId = getActiveWorkspaceId(request);
    Workspace workspace = workspaceRepository.findById(workspaceId, user);

    Authorizations authorizations = getAuthorizations(request, user);

    JSONObject visibilityJson =
        GraphUtil.updateVisibilitySourceAndAddWorkspaceId(null, visibilitySource, workspaceId);
    LumifyVisibility visibility = this.visibilityTranslator.toVisibility(visibilityJson);
    if (!graph.isVisibilityValid(visibility.getVisibility(), authorizations)) {
      LOGGER.warn(
          "%s is not a valid visibility for %s user", visibilitySource, user.getDisplayName());
      respondWithBadRequest(response, "visibilitySource", STRINGS.getString("visibility.invalid"));
      chain.next(request, response);
      return;
    }

    Object id = resolvedVertexId == null ? graph.getIdGenerator().nextId() : resolvedVertexId;

    Concept concept = ontologyRepository.getConceptByIRI(conceptId);

    final Vertex artifactVertex = graph.getVertex(artifactId, authorizations);
    LumifyVisibility lumifyVisibility = visibilityTranslator.toVisibility(visibilityJson);
    Map<String, Object> metadata = new HashMap<String, Object>();
    LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setMetadata(metadata, visibilityJson);
    ElementMutation<Vertex> vertexMutation;
    Vertex vertex;
    if (resolvedVertexId != null) {
      vertex = graph.getVertex(id, authorizations);
      vertexMutation = vertex.prepareMutation();
    } else {
      vertexMutation = graph.prepareVertex(id, lumifyVisibility.getVisibility());
      GraphUtil.addJustificationToMutation(
          vertexMutation, justificationText, sourceInfo, lumifyVisibility);

      CONCEPT_TYPE.setProperty(
          vertexMutation, conceptId, metadata, lumifyVisibility.getVisibility());
      TITLE.addPropertyValue(
          vertexMutation, MULTI_VALUE_KEY, title, metadata, lumifyVisibility.getVisibility());

      vertex = vertexMutation.save(authorizations);

      auditRepository.auditVertexElementMutation(
          AuditAction.UPDATE, vertexMutation, vertex, "", user, lumifyVisibility.getVisibility());

      LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setProperty(
          vertexMutation, visibilityJson, metadata, lumifyVisibility.getVisibility());

      this.graph.flush();

      workspaceRepository.updateEntityOnWorkspace(
          workspace, vertex.getId(), false, null, null, user);
    }

    // TODO: a better way to check if the same edge exists instead of looking it up every time?
    Edge edge =
        graph.addEdge(
            artifactVertex,
            vertex,
            this.artifactHasEntityIri,
            lumifyVisibility.getVisibility(),
            authorizations);
    LumifyVisibilityProperties.VISIBILITY_JSON_PROPERTY.setProperty(
        edge, visibilityJson, metadata, lumifyVisibility.getVisibility(), authorizations);

    auditRepository.auditRelationship(
        AuditAction.CREATE,
        artifactVertex,
        vertex,
        edge,
        "",
        "",
        user,
        lumifyVisibility.getVisibility());

    TermMentionRowKey termMentionRowKey;
    if (termMentionRowKeyString != null) {
      termMentionRowKey = new TermMentionRowKey(RowKeyHelper.jsonDecode(termMentionRowKeyString));
    } else {
      termMentionRowKey =
          new TermMentionRowKey(
              artifactId, propertyKey, mentionStart, mentionEnd, edge.getId().toString());
    }
    TermMentionModel termMention = new TermMentionModel(termMentionRowKey);
    termMention
        .getMetadata()
        .setSign(title, lumifyVisibility.getVisibility())
        .setOntologyClassUri(concept.getDisplayName(), lumifyVisibility.getVisibility())
        .setConceptGraphVertexId(concept.getTitle(), lumifyVisibility.getVisibility())
        .setVertexId(vertex.getId().toString(), lumifyVisibility.getVisibility())
        .setEdgeId(edge.getId().toString(), lumifyVisibility.getVisibility());
    termMentionRepository.save(termMention);

    vertexMutation.addPropertyValue(
        graph.getIdGenerator().nextId().toString(),
        LumifyProperties.ROW_KEY.getPropertyName(),
        termMentionRowKey.toString(),
        metadata,
        lumifyVisibility.getVisibility());
    vertexMutation.save(authorizations);

    this.graph.flush();
    workQueueRepository.pushTextUpdated(artifactId);

    workQueueRepository.pushElement(edge);

    JSONObject result = new JSONObject();
    result.put("success", true);
    respondWithJson(response, result);
  }