public void auditEdgeElementMutation(
     AuditAction action,
     ElementMutation<Edge> edgeElementMutation,
     Edge edge,
     Vertex sourceVertex,
     Vertex destVertex,
     String process,
     User user,
     Visibility visibility) {
   if (edgeElementMutation instanceof ExistingElementMutation) {
     Edge oldEdge = (Edge) ((ExistingElementMutation) edgeElementMutation).getElement();
     for (Property property : edgeElementMutation.getProperties()) {
       // TODO handle multi-valued properties
       Object oldPropertyValue = oldEdge.getPropertyValue(property.getName());
       Object newPropertyValue = property.getValue();
       checkNotNull(newPropertyValue, "new property value cannot be null");
       if (!newPropertyValue.equals(oldPropertyValue)) {
         auditRelationshipProperty(
             action,
             sourceVertex.getId().toString(),
             destVertex.getId().toString(),
             property.getName(),
             oldPropertyValue,
             newPropertyValue,
             edge,
             process,
             "",
             user,
             visibility);
       }
     }
   } else {
     auditRelationship(
         AuditAction.CREATE, sourceVertex, destVertex, edge, process, "", user, visibility);
     for (Property property : edgeElementMutation.getProperties()) {
       // TODO handle multi-valued properties
       Object newPropertyValue = property.getValue();
       checkNotNull(newPropertyValue, "new property value cannot be null");
       auditRelationshipProperty(
           action,
           sourceVertex.getId().toString(),
           destVertex.getId().toString(),
           property.getName(),
           null,
           newPropertyValue,
           edge,
           process,
           "",
           user,
           visibility);
     }
   }
 }
  @Override
  public void handle(HttpServletRequest request, HttpServletResponse response, HandlerChain chain)
      throws Exception {
    User user = getUser(request);
    Authorizations authorizations = getAuthorizations(request, user);
    String workspaceId = getWorkspaceId(request);

    String graphVertexId = (String) request.getAttribute("graphVertexId");
    long offset = getOptionalParameterLong(request, "offset", 0);
    long size = getOptionalParameterLong(request, "size", 25);

    Vertex vertex = graph.getVertex(graphVertexId, authorizations);
    if (vertex == null) {
      respondWithNotFound(response);
      return;
    }

    Iterable<Edge> edges = vertex.getEdges(Direction.BOTH, authorizations);

    JSONObject json = new JSONObject();
    JSONArray relationshipsJson = new JSONArray();
    long referencesAdded = 0, skipped = 0, totalReferences = 0;
    for (Edge edge : edges) {
      Vertex otherVertex = edge.getOtherVertex(vertex.getId(), authorizations);
      if (otherVertex == null) { // user doesn't have access to other side of edge
        continue;
      }

      if (edge.getLabel().equals("http://lumify.io/dev#rawHasEntity")) {
        totalReferences++;
        if (referencesAdded >= size) continue;
        if (skipped < offset) {
          skipped++;
          continue;
        }

        referencesAdded++;
      }

      JSONObject relationshipJson = new JSONObject();
      relationshipJson.put("relationship", toJson(edge, workspaceId));
      relationshipJson.put("vertex", toJson(otherVertex, workspaceId));
      relationshipsJson.put(relationshipJson);
    }
    json.put("totalReferences", totalReferences);
    json.put("relationships", relationshipsJson);

    respondWithJson(response, json);
  }
  public List<Audit> auditRelationshipProperty(
      AuditAction action,
      String sourceId,
      String destId,
      String propertyName,
      Object oldValue,
      Object newValue,
      Edge edge,
      String process,
      String comment,
      User user,
      Visibility visibility) {
    checkNotNull(action, "action cannot be null");
    checkNotNull(sourceId, "sourceId cannot be null");
    checkNotNull(sourceId.length() > 0, "sourceId cannot be empty");
    checkNotNull(destId, "destId cannot be null");
    checkNotNull(destId.length() > 0, "destId cannot be empty");
    checkNotNull(propertyName, "propertyName cannot be null");
    checkNotNull(propertyName.length() > 0, "propertyName cannot be empty");
    checkNotNull(edge, "edge cannot be null");
    checkNotNull(process, "process cannot be null");
    checkNotNull(comment, "comment cannot be null");
    checkNotNull(user, "user cannot be null");

    Audit auditSourceDest = new Audit(AuditRowKey.build(sourceId, destId));
    Audit auditDestSource = new Audit(AuditRowKey.build(destId, sourceId));
    Audit auditEdge = new Audit(AuditRowKey.build(edge.getId()));
    visibility = orVisibility(visibility);

    auditSourceDest
        .getAuditCommon()
        .setUser(user, visibility)
        .setAction(action, visibility)
        .setType(OntologyRepository.TYPE_PROPERTY, visibility)
        .setComment(comment, visibility)
        .setProcess(process, visibility)
        .setUnixBuildTime(
            versionService.getUnixBuildTime() != null ? versionService.getUnixBuildTime() : -1L,
            visibility)
        .setScmBuildNumber(
            versionService.getScmBuildNumber() != null ? versionService.getScmBuildNumber() : "",
            visibility)
        .setVersion(
            versionService.getVersion() != null ? versionService.getVersion() : "", visibility);

    auditDestSource
        .getAuditCommon()
        .setUser(user, visibility)
        .setAction(action, visibility)
        .setType(OntologyRepository.TYPE_PROPERTY, visibility)
        .setComment(comment, visibility)
        .setProcess(process, visibility)
        .setUnixBuildTime(
            versionService.getUnixBuildTime() != null ? versionService.getUnixBuildTime() : -1L,
            visibility)
        .setScmBuildNumber(
            versionService.getScmBuildNumber() != null ? versionService.getScmBuildNumber() : "",
            visibility)
        .setVersion(
            versionService.getVersion() != null ? versionService.getVersion() : "", visibility);

    auditEdge
        .getAuditCommon()
        .setUser(user, visibility)
        .setAction(action, visibility)
        .setType(OntologyRepository.TYPE_PROPERTY, visibility)
        .setComment(comment, visibility)
        .setProcess(process, visibility)
        .setUnixBuildTime(
            versionService.getUnixBuildTime() != null ? versionService.getUnixBuildTime() : -1L,
            visibility)
        .setScmBuildNumber(
            versionService.getScmBuildNumber() != null ? versionService.getScmBuildNumber() : "",
            visibility)
        .setVersion(
            versionService.getVersion() != null ? versionService.getVersion() : "", visibility);

    if (oldValue != null && !oldValue.equals("")) {
      auditDestSource.getAuditProperty().setPreviousValue(oldValue, visibility);
      auditSourceDest.getAuditProperty().setPreviousValue(oldValue, visibility);
      auditEdge.getAuditProperty().setPreviousValue(oldValue, visibility);
    }
    if (action == AuditAction.DELETE) {
      auditDestSource.getAuditProperty().setNewValue("", visibility);
      auditSourceDest.getAuditProperty().setNewValue("", visibility);
      auditEdge.getAuditProperty().setNewValue("", visibility);
    } else {
      // TODO handle multi-valued properties
      auditDestSource.getAuditProperty().setNewValue(newValue, visibility);
      auditSourceDest.getAuditProperty().setNewValue(newValue, visibility);
      auditEdge.getAuditProperty().setNewValue(newValue, visibility);
    }
    auditDestSource.getAuditProperty().setPropertyName(propertyName, visibility);
    auditSourceDest.getAuditProperty().setPropertyName(propertyName, visibility);
    auditEdge.getAuditProperty().setPropertyName(propertyName, visibility);

    List<Audit> audits = Lists.newArrayList(auditSourceDest, auditDestSource);
    saveMany(audits);
    return audits;
  }
  public List<Audit> auditRelationship(
      AuditAction action,
      Vertex sourceVertex,
      Vertex destVertex,
      Edge edge,
      String process,
      String comment,
      User user,
      Visibility visibility) {
    checkNotNull(action, "action cannot be null");
    checkNotNull(sourceVertex, "sourceVertex cannot be null");
    checkNotNull(destVertex, "destVertex cannot be null");
    checkNotNull(edge, "edge cannot be null");
    checkNotNull(process, "process cannot be null");
    checkNotNull(comment, "comment cannot be null");
    checkNotNull(user, "user cannot be null");

    Audit auditSourceDest = new Audit(AuditRowKey.build(sourceVertex.getId(), destVertex.getId()));
    Audit auditDestSource = new Audit(AuditRowKey.build(destVertex.getId(), sourceVertex.getId()));
    Audit auditEdge = new Audit(AuditRowKey.build(edge.getId()));
    visibility = orVisibility(visibility);

    List<Audit> audits = new ArrayList<Audit>();
    String displayLabel = ontologyRepository.getDisplayNameForLabel(edge.getLabel());
    audits.add(
        auditRelationshipHelper(
            auditSourceDest,
            action,
            sourceVertex,
            destVertex,
            displayLabel,
            process,
            comment,
            user,
            visibility));
    audits.add(
        auditRelationshipHelper(
            auditDestSource,
            action,
            sourceVertex,
            destVertex,
            displayLabel,
            process,
            comment,
            user,
            visibility));
    auditEdge
        .getAuditCommon()
        .setUser(user, visibility)
        .setAction(action, visibility)
        .setType(OntologyRepository.TYPE_RELATIONSHIP, visibility)
        .setComment(comment, visibility)
        .setProcess(process, visibility)
        .setUnixBuildTime(
            versionService.getUnixBuildTime() != null ? versionService.getUnixBuildTime() : -1L,
            visibility)
        .setScmBuildNumber(
            versionService.getScmBuildNumber() != null ? versionService.getScmBuildNumber() : "",
            visibility)
        .setVersion(
            versionService.getVersion() != null ? versionService.getVersion() : "", visibility);

    auditEdge
        .getAuditRelationship()
        .setSourceId(sourceVertex.getId(), visibility)
        .setSourceType(CONCEPT_TYPE.getPropertyValue(sourceVertex), visibility)
        .setSourceTitle(TITLE.getPropertyValue(sourceVertex), visibility)
        .setDestId(destVertex.getId(), visibility)
        .setDestTitle(TITLE.getPropertyValue(destVertex), visibility)
        .setDestType(CONCEPT_TYPE.getPropertyValue(destVertex), visibility)
        .setLabel(displayLabel, visibility);

    audits.add(auditEdge);

    saveMany(audits);
    return audits;
  }