@Restrict("#{s:hasPermission('Node', 'edit', documentHistory.currentFile)}")
 public String rollback() {
   statusMessages.addFromResourceBundleOrDefault(
       INFO,
       "lacewiki.msg.RollingBackDocument",
       "Rolling document back to revision {0}",
       selectedHistoricalFile.getRevision());
   return "rollback";
 }
  public void displayHistoricalRevision() {
    log.debug("displaying historical file id: " + selectedHistoricalFile.getHistoricalFileId());

    displayedHistoricalFile = selectedHistoricalFile;
    diffResult = null;

    statusMessages.addFromResourceBundleOrDefault(
        INFO,
        "lacewiki.msg.DiffOldVersionDisplayed",
        "Showing historical revision {0}",
        selectedHistoricalFile.getRevision());
  }
  // This methods takes the historicalFileId parameter to load a revision from the DB
  public void diff() {
    init(); // TODO: Why doesn't Seam execute my page action but instead s:link action="diff" in a
            // fake RENDER RESPONSE?!?
    displayedHistoricalFile = null;

    if (historicalFileId == null) return;
    selectedHistoricalFile =
        wikiNodeDAO.findHistoricalFile(
            getCurrentFile().getHistoricalEntityName(), historicalFileId);
    if (selectedHistoricalFile == null) {
      statusMessages.addFromResourceBundleOrDefault(
          ERROR,
          "lacewiki.msg.HistoricalNodeNotFound",
          "Couldn't find historical node: {0}",
          historicalFileId);
      return;
    }
    diffHistoricalRevision();
  }
  public void diffHistoricalRevision() {
    log.debug("diffing historical file id: " + selectedHistoricalFile.getHistoricalFileId());

    String[] a = ((WikiDocument) selectedHistoricalFile).getContent().split("\n");
    String[] b = ((WikiDocument) currentFile).getContent().split("\n");

    StringBuilder result = new StringBuilder();
    List<Diff.Difference> differences = new Diff(a, b).diff();

    // TODO: Externalize and i18n these strings
    for (Diff.Difference diff : differences) {
      int delStart = diff.getDeletedStart();
      int delEnd = diff.getDeletedEnd();
      int addStart = diff.getAddedStart();
      int addEnd = diff.getAddedEnd();
      String type =
          delEnd != Diff.NONE && addEnd != Diff.NONE
              ? "changed"
              : (delEnd == Diff.NONE ? "added" : "deleted");

      // Info line
      result.append("<div class=\"diffInfo\">");
      result.append("From ");
      result.append(delStart == delEnd || delEnd == Diff.NONE ? "line" : "lines");
      result.append(" ");
      result.append(delStart);
      if (delEnd != Diff.NONE && delStart != delEnd) {
        result.append(" to ").append(delEnd);
      }
      result.append(" ").append(type).append(" to ");
      result.append(addStart == addEnd || addEnd == Diff.NONE ? "line" : "lines");
      result.append(" ");
      result.append(addStart);
      if (addEnd != Diff.NONE && addStart != addEnd) {
        result.append(" to ").append(addEnd);
      }
      result.append(":");
      result.append("</div>\n");

      if (delEnd != Diff.NONE) {
        result.append("<div class=\"diffDeleted\">");
        for (int lnum = delStart; lnum <= delEnd; ++lnum) {
          result.append(WikiUtil.escapeHtml(a[lnum], false, false)).append("<br/>");
        }
        result.append("</div>");
        if (addEnd != Diff.NONE) {
          // result.append("----------------------------").append("\n");
        }
      }
      if (addEnd != Diff.NONE) {
        result.append("<div class=\"diffAdded\">");
        for (int lnum = addStart; lnum <= addEnd; ++lnum) {
          result.append(WikiUtil.escapeHtml(b[lnum], false, false)).append("<br/>");
        }
        result.append("</div>");
      }
    }

    diffResult = result.toString();

    statusMessages.addFromResourceBundleOrDefault(
        INFO,
        "lacewiki.msg.DiffCreated",
        "Comparing current revision with historical revision {0}",
        selectedHistoricalFile.getRevision());
  }