@Override
 public void deleteRelation(
     CoreSession session,
     DocumentModel from,
     DocumentModel to,
     String predicate,
     boolean includeStatementsInEvents)
     throws ClientException {
   QNameResource fromResource =
       (QNameResource)
           getRelationManager().getResource(RelationConstants.DOCUMENT_NAMESPACE, from, null);
   QNameResource toResource =
       (QNameResource)
           getRelationManager().getResource(RelationConstants.DOCUMENT_NAMESPACE, to, null);
   Resource predicateResource = new ResourceImpl(predicate);
   Graph graph = getRelationManager().getGraphByName(RelationConstants.GRAPH_NAME);
   List<Statement> statements = graph.getStatements(fromResource, predicateResource, toResource);
   if (statements == null || statements.size() == 0) {
     // Silent ignore the deletion as it doesn't exist
     return;
   }
   for (Statement stmt : statements) {
     deleteRelation(session, stmt);
   }
 }
  @Override
  public void addRelation(
      CoreSession session,
      DocumentModel from,
      Node toResource,
      String predicate,
      boolean inverse,
      boolean includeStatementsInEvents,
      String comment)
      throws ClientException {
    Graph graph = getRelationManager().getGraphByName(RelationConstants.GRAPH_NAME);
    QNameResource fromResource = getNodeFromDocumentModel(from);

    Resource predicateResource = new ResourceImpl(predicate);
    Statement stmt = null;
    List<Statement> statements = null;
    if (inverse) {
      stmt = new StatementImpl(toResource, predicateResource, fromResource);
      statements = graph.getStatements(toResource, predicateResource, fromResource);
      if (statements != null && statements.size() > 0) {
        throw new RelationAlreadyExistsException();
      }
    } else {
      stmt = new StatementImpl(fromResource, predicateResource, toResource);
      statements = graph.getStatements(fromResource, predicateResource, toResource);
      if (statements != null && statements.size() > 0) {
        throw new RelationAlreadyExistsException();
      }
    }

    // Comment ?
    if (!StringUtils.isEmpty(comment)) {
      stmt.addProperty(RelationConstants.COMMENT, new LiteralImpl(comment));
    }
    Literal now = RelationDate.getLiteralDate(new Date());
    if (stmt.getProperties(RelationConstants.CREATION_DATE) == null) {
      stmt.addProperty(RelationConstants.CREATION_DATE, now);
    }
    if (stmt.getProperties(RelationConstants.MODIFICATION_DATE) == null) {
      stmt.addProperty(RelationConstants.MODIFICATION_DATE, now);
    }

    if (session.getPrincipal() != null && stmt.getProperty(RelationConstants.AUTHOR) != null) {
      stmt.addProperty(RelationConstants.AUTHOR, new LiteralImpl(session.getPrincipal().getName()));
    }

    // notifications

    Map<String, Serializable> options = new HashMap<String, Serializable>();
    String currentLifeCycleState = from.getCurrentLifeCycleState();
    options.put(CoreEventConstants.DOC_LIFE_CYCLE, currentLifeCycleState);
    if (includeStatementsInEvents) {
      putStatements(options, stmt);
    }
    options.put(RelationEvents.GRAPH_NAME_EVENT_KEY, RelationConstants.GRAPH_NAME);

    // before notification
    notifyEvent(RelationEvents.BEFORE_RELATION_CREATION, from, options, comment, session);

    // add statement
    graph.add(stmt);

    // XXX AT: try to refetch it from the graph so that resources are
    // transformed into qname resources: useful for indexing
    if (includeStatementsInEvents) {
      putStatements(options, graph.getStatements(stmt));
    }

    // after notification
    notifyEvent(RelationEvents.AFTER_RELATION_CREATION, from, options, comment, session);
  }