/**
   * List the justifications for the triple with the id given as argument. For informational
   * purposes.
   *
   * @param tripleId
   * @return
   * @throws SailException
   */
  public CloseableIteration<Justification, SailException> justify(long tripleId)
      throws SailException {
    try {
      final KiWiReasoningConnection connection = persistence.getConnection();

      return new ExceptionConvertingIteration<Justification, SailException>(
          connection.listJustificationsForTriple(tripleId)) {
        /**
         * Converts an exception from the underlying iteration to an exception of type <tt>X</tt>.
         */
        @Override
        protected SailException convert(Exception e) {
          return new SailException(e);
        }

        @Override
        protected void handleClose() throws SailException {
          super.handleClose();

          try {
            connection.commit();
            connection.close();
          } catch (SQLException ex) {
            throw new SailException("database error while committing/closing connection");
          }
        }
      };
    } catch (SQLException ex) {
      throw new SailException("cannot list programs in database", ex);
    }
  }
 /**
  * Return the program with the given name. In case the program does not exist, the method will
  * return null.
  *
  * @param name the unique name of the program to retrieve
  * @return the parsed program, or null in case a program with the given name does not exist
  * @throws SailException in case an error occurs
  */
 public Program getProgram(String name) throws SailException {
   try {
     KiWiReasoningConnection connection = persistence.getConnection();
     try {
       // should not throw an exception and the program should have a database ID afterwards
       Program p = connection.loadProgram(name);
       connection.commit();
       return p;
     } finally {
       connection.close();
     }
   } catch (SQLException ex) {
     throw new SailException("cannot load program from database", ex);
   }
 }
 /**
  * Remove the program with the given name. This method will first remove the program from the
  * database and then inform the reasoning engine to run cleanups.
  *
  * <p>If a program with this name does not exist, does nothing
  *
  * @param name the unique name of the program to remove
  * @throws SailException
  */
 public void deleteProgram(String name) throws SailException {
   try {
     KiWiReasoningConnection connection = persistence.getConnection();
     try {
       Program p = connection.loadProgram(name);
       connection.deleteProgram(p);
       connection.commit();
     } finally {
       connection.close();
     }
   } catch (SQLException ex) {
     throw new SailException("cannot load program from database", ex);
   }
   engine.loadPrograms();
   engine.notifyRemoveRules();
 }
  /**
   * Update the program given as argument. This method will first calculate the difference between
   * the previous version of the program and the new version of the program. It then updates the
   * program in the database and notifies the engine of all removed and added rules.
   *
   * @param program the updated version of the program
   * @throws SailException in case a database error occurs
   */
  public void updateProgram(Program program) throws SailException {
    Set<Rule> added = new HashSet<Rule>();
    Set<Rule> removed = new HashSet<Rule>();
    try {
      KiWiReasoningConnection connection = persistence.getConnection();
      try {
        // load old version of program and calculate difference
        Program old = connection.loadProgram(program.getName());
        if (old != null) {
          for (Rule r : old.getRules()) {
            if (!program.getRules().contains(r)) {
              removed.add(r);
            }
          }
          for (Rule r : program.getRules()) {
            if (!old.getRules().contains(r)) {
              added.add(r);
            }
          }
        }

        // store program in the database
        connection.updateProgram(program);
        connection.commit();
      } finally {
        connection.close();
      }
    } catch (SQLException ex) {
      throw new SailException("cannot store program in database", ex);
    }

    engine.loadPrograms();

    // if rules have been removed, clean up
    if (removed.size() > 0) {
      engine.notifyRemoveRules();
    }

    // now add all added rules to the reasoner
    for (Rule rule : added) {
      engine.notifyAddRule(rule);
    }
  }
  /**
   * Add a program to the reasoner. The program is persisted to the database and the reasoning
   * engine is notified of the added rules and immediately calculates the inferences. Inferencing in
   * this case is synchronous, so the method only returns when the first round of reasoning is
   * completed for all added rules.
   *
   * <p>If a program with this name already exists, a SailException is thrown. To update existing
   * programs, please use updateProgram().
   *
   * @param program the program data in KWRL syntax
   * @throws SailException in case the program already exists
   */
  public void addProgram(Program program) throws SailException {
    // store program in the database
    try {
      KiWiReasoningConnection connection = persistence.getConnection();
      try {
        // should not throw an exception and the program should have a database ID afterwards
        connection.storeProgram(program);
        connection.commit();
      } finally {
        connection.close();
      }
    } catch (SQLException ex) {
      throw new SailException("cannot store program in database", ex);
    }

    engine.loadPrograms();

    // now add all added rules to the reasoner
    for (Rule rule : program.getRules()) {
      engine.notifyAddRule(rule);
    }
  }
  @Override
  public void initialize() throws SailException {
    synchronized (this) {
      if (!initialized) {
        super.initialize();

        KiWiStore store = getBaseStore();

        try {
          persistence = new KiWiReasoningPersistence(store.getPersistence(), getValueFactory());
          persistence.initDatabase();

          engine = new ReasoningEngine(persistence, this, config);
          addTransactionListener(engine);

          initialized = true;
        } catch (SQLException e) {
          log.error("error initializing reasoning database", e);
          throw new SailException("error initializing reasoning database", e);
        }
      }
    }
  }