/**
   * Used to write Resources for a Subject. Literals will by-pass this method and use "Literal"
   * method.
   *
   * @param predicate PredicateNode
   * @param object ObjectNode
   * @param writer PrintWriter
   * @throws GraphException
   */
  protected void writeStatement(
      Graph graph,
      SubjectNode subject,
      PredicateNode predicate,
      ObjectNode object,
      PrintWriter writer)
      throws GraphException {

    // Literals are written differently
    if (object instanceof Literal) {

      this.writeStatement(graph, subject, predicate, (Literal) object, writer);
    } else if (object instanceof BlankNode) {

      // write as:  <predicateURI> *blank node as subject* </predicateURI>
      writer.println("    <" + this.getURI(predicate) + ">");

      // write blank node as a "subject"
      this.writeSubject(graph, (BlankNode) object, writer);

      writer.println("    </" + this.getURI(predicate) + ">");
    } else if (subject instanceof BlankNode) {

      // predicatNode representing RDF Type
      PredicateNode rdfTypeNode = null;

      try {

        rdfTypeNode = graph.getElementFactory().createResource(RDF.TYPE);
      } catch (GraphElementFactoryException factoryException) {

        throw new GraphException("Could not create RDF Type node.", factoryException);
      }

      // do not write the RDF Type element
      if (!rdfTypeNode.equals(predicate)) {

        // write as:  <predicateURI rdf:resource="resourceURI"/>
        writer.println(
            "    <"
                + this.getURI(predicate)
                + " "
                + RDF_PREFIX
                + ":resource=\""
                + this.getNodeString(object)
                + "\"/>");
      }
    } else {

      // write as:  <predicateURI rdf:resource="resourceURI"/>
      writer.println(
          "    <"
              + this.getURI(predicate)
              + " "
              + RDF_PREFIX
              + ":resource=\""
              + this.getNodeString(object)
              + "\"/>");
    }
  }
  /**
   * Finds the RDF Type for a given subject.
   *
   * @param graph Graph
   * @param subject SubjectNode
   * @throws GraphException
   * @return ObjectNode
   */
  protected ObjectNode getSubjectType(Graph graph, SubjectNode subject) throws GraphException {

    // value to be returned
    ObjectNode type = null;

    // validate graph
    if ((graph == null)) {
      throw new IllegalArgumentException("Graph argument must not be null.");
    }

    // predicatNode representing RDF Type
    PredicateNode rdfType = null;

    try {
      rdfType = graph.getElementFactory().createResource(RDF.TYPE);
    } catch (GraphElementFactoryException factoryException) {

      throw new GraphException("Could not create RDF Type node.", factoryException);
    }

    // get the Subject's RDF type
    ClosableIterator<Triple> typeIter = graph.find(subject, rdfType, null);

    if (typeIter != null) {

      // validate "first" triple and extract it's object (rdf type)
      if (typeIter.hasNext()) {

        Triple typeTriple = typeIter.next();

        if (typeTriple != null) {
          type = ((Triple) typeTriple).getObject();
        } else {
          throw new GraphException(
              "Could not find RDF type for Subject: " + subject + " . Invalid Triple returned.");
        }
      }

      // close the Iterator
      typeIter.close();
    }

    return type;
  }
  /**
   * Populates the namespaces map with default namespaces and namespaces used by the graph.
   *
   * @param graph Graph
   * @throws GraphException
   */
  protected void populateNamespaces(Graph graph) throws GraphException {

    // default namespaces
    namespaces = new HashMap<String, String>();
    namespaces.put(RDF_PREFIX, RDF.BASE_URI.toString());
    namespaces.put(RDFS_PREFIX, RDFS.BASE_URI.toString());
    namespaces.put("owl", "http://www.w3.org/2002/07/owl#");
    namespaces.put("dc", "http://purl.org/dc/elements/1.1/");

    // validate graph before reading
    if (graph == null) {
      throw new IllegalArgumentException("Graph argument is null.");
    }

    // get all statements
    ClosableIterator<Triple> tripleIter = graph.find(null, null, null);

    if (tripleIter != null) {

      while (tripleIter.hasNext()) {

        // get the next triple
        Triple triple = tripleIter.next();

        if (triple != null) {

          // evaluate subject
          SubjectNode subject = triple.getSubject();
          if (subject instanceof URIReference) {
            addNamespaceURI(((URIReference) subject).getURI());
          }

          // evaluate predicate (must be URIReference)
          PredicateNode predicate = triple.getPredicate();
          addNamespaceURI(((URIReference) predicate).getURI());

          // evaluate object
          ObjectNode object = triple.getObject();
          if (object instanceof URIReference) {
            addNamespaceURI(((URIReference) object).getURI());
          }
        }
      }

      // close the Iterator
      tripleIter.close();
    }
  }
  /**
   * Writes the Graph's statements as RDF/XML to the print Writer.
   *
   * @param out PrintWriter
   * @throws IOException
   */
  protected void writeBody(Graph graph, PrintWriter out) throws IOException, GraphException {

    // validate
    if ((out != null) && (graph != null)) {

      // iterator used to access subjects
      ClosableIterator<Triple> subjectIter = graph.find(null, null, null);

      // write every (unique) subject
      if (subjectIter != null) {

        Set<SubjectNode> writtenSubjectSet = new HashSet<SubjectNode>();

        while (subjectIter.hasNext()) {

          // get the next triple
          Triple triple = subjectIter.next();

          if (triple != null) {

            SubjectNode subject = ((Triple) triple).getSubject();

            if (!writtenSubjectSet.contains(subject)) {
              this.writeSubject(graph, subject, out);
              writtenSubjectSet.add(subject);
            }
          }
        }

        // close the Iterator
        subjectIter.close();
      }
    } else {

      // message for exception to be thrown
      String message = "Could not write Graph. Invlaid arguments provided. ";

      if (out == null) message += "Writer is null. ";
      if (graph == null) message += "Graph is null. ";

      throw new IllegalArgumentException(message);
    }
  }
  /**
   * Writes the Resources for a subject (one per line).
   *
   * <p>eg. &lt;predicateURI rdf:resource="resourceURI"/&gt; (&lt;predicateURI
   * rdf:nodeID="resourceURI"/&gt; for Blank Nodes)
   *
   * @param graph Graph
   * @param subject SubjectNode
   * @param writer PrintWriter
   * @throws GraphException
   */
  protected void writeSubjectBody(Graph graph, SubjectNode subject, PrintWriter writer)
      throws GraphException {

    // validate graph
    /*
    if (! (graph instanceof JRDFGraph)) {

      throw new IllegalArgumentException("Graph must be of type JRDFGraph");
    }
    */

    // get all statements for the Subject
    ClosableIterator<Triple> tripleIter = graph.find(subject, null, null);

    if (tripleIter != null) {

      // current Triple
      Object triple = null;

      // evaluate all triples
      while (tripleIter.hasNext()) {

        triple = tripleIter.next();

        // validate triple
        if (triple != null) {

          // retrieve Predicate and Object
          PredicateNode predicate = ((Triple) triple).getPredicate();
          ObjectNode object = ((Triple) triple).getObject();

          // Literals and Resources are written differently
          if (object != null) {
            writeStatement(graph, subject, predicate, object, writer);
          }
        }
      }

      // close the Iterator
      tripleIter.close();
    }
  }