| 1 |  |  package liquibase.dbdoc; | 
  | 2 |  |   | 
  | 3 |  |  import liquibase.change.Change; | 
  | 4 |  |  import liquibase.changelog.ChangeSet; | 
  | 5 |  |  import liquibase.database.Database; | 
  | 6 |  |  import liquibase.exception.DatabaseException; | 
  | 7 |  |  import liquibase.exception.DatabaseHistoryException; | 
  | 8 |  |  import liquibase.util.LiquibaseUtil; | 
  | 9 |  |  import liquibase.util.StringUtils; | 
  | 10 |  |   | 
  | 11 |  |  import java.io.File; | 
  | 12 |  |  import java.io.FileWriter; | 
  | 13 |  |  import java.io.IOException; | 
  | 14 |  |  import java.text.DateFormat; | 
  | 15 |  |  import java.util.Date; | 
  | 16 |  |  import java.util.List; | 
  | 17 |  |   | 
  | 18 |  |  public abstract class HTMLWriter { | 
  | 19 |  |      protected File outputDir; | 
  | 20 |  |      protected Database database; | 
  | 21 |  |   | 
  | 22 | 0 |      public HTMLWriter(File outputDir, Database database) { | 
  | 23 | 0 |          this.outputDir = outputDir; | 
  | 24 | 0 |          this.database = database; | 
  | 25 | 0 |          if (!outputDir.exists()) { | 
  | 26 | 0 |              outputDir.mkdirs(); | 
  | 27 |  |          } | 
  | 28 | 0 |      } | 
  | 29 |  |   | 
  | 30 |  |      protected abstract void writeCustomHTML(FileWriter fileWriter, Object object, List<Change> changes, | 
  | 31 |  |              Database database) throws IOException; | 
  | 32 |  |   | 
  | 33 |  |      private FileWriter createFileWriter(Object object) throws IOException { | 
  | 34 | 0 |          return new FileWriter(new File(outputDir, object.toString().toLowerCase() + ".html")); | 
  | 35 |  |      } | 
  | 36 |  |   | 
  | 37 |  |      public void writeHTML(Object object, List<Change> ranChanges, List<Change> changesToRun, String changeLog) | 
  | 38 |  |              throws IOException, DatabaseHistoryException, DatabaseException { | 
  | 39 | 0 |          FileWriter fileWriter = createFileWriter(object); | 
  | 40 |  |   | 
  | 41 |  |          try { | 
  | 42 | 0 |              fileWriter.append("<html>"); | 
  | 43 | 0 |              writeHeader(object, fileWriter); | 
  | 44 | 0 |              fileWriter.append("<body BGCOLOR=\"white\" onload=\"windowTitle();\">"); | 
  | 45 |  |   | 
  | 46 | 0 |              fileWriter.append("<H2>").append(createTitle(object)).append("</H2>\n"); | 
  | 47 |  |   | 
  | 48 | 0 |              writeBody(fileWriter, object, ranChanges, changesToRun); | 
  | 49 |  |   | 
  | 50 | 0 |              writeFooter(fileWriter, changeLog); | 
  | 51 |  |   | 
  | 52 | 0 |              fileWriter.append("</body>"); | 
  | 53 | 0 |              fileWriter.append("</html>"); | 
  | 54 |  |          } finally { | 
  | 55 | 0 |              fileWriter.close(); | 
  | 56 | 0 |          } | 
  | 57 |  |   | 
  | 58 | 0 |      } | 
  | 59 |  |   | 
  | 60 |  |      private void writeFooter(FileWriter fileWriter, String changeLog) throws IOException { | 
  | 61 | 0 |          fileWriter.append("<hr>Generated: "); | 
  | 62 | 0 |          fileWriter.append(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date())); | 
  | 63 | 0 |          fileWriter.append("<BR>Against: "); | 
  | 64 | 0 |          fileWriter.append(database.toString()); | 
  | 65 | 0 |          fileWriter.append("<BR>Change Log: "); | 
  | 66 | 0 |          fileWriter.append(changeLog); | 
  | 67 | 0 |          fileWriter.append("<BR><BR>Generated By: "); | 
  | 68 | 0 |          fileWriter.append("<a href='http://www.liquibase.org' target='_TOP'>Liquibase ") | 
  | 69 |  |                  .append(LiquibaseUtil.getBuildVersion()).append("</a>"); | 
  | 70 | 0 |      } | 
  | 71 |  |   | 
  | 72 |  |      protected void writeBody(FileWriter fileWriter, Object object, List<Change> ranChanges, List<Change> changesToRun) | 
  | 73 |  |              throws IOException, DatabaseHistoryException, DatabaseException { | 
  | 74 | 0 |          writeCustomHTML(fileWriter, object, ranChanges, database); | 
  | 75 | 0 |          writeChanges("Pending Changes", fileWriter, changesToRun); | 
  | 76 | 0 |          writeChanges("Past Changes", fileWriter, ranChanges); | 
  | 77 | 0 |      } | 
  | 78 |  |   | 
  | 79 |  |      protected void writeTable(String title, List<List<String>> cells, FileWriter fileWriter) throws IOException { | 
  | 80 | 0 |          fileWriter.append("<P>"); | 
  | 81 | 0 |          int colspan = 0; | 
  | 82 | 0 |          if (cells.size() == 0) { | 
  | 83 | 0 |              colspan = 0; | 
  | 84 |  |          } else { | 
  | 85 | 0 |              colspan = cells.get(0).size(); | 
  | 86 |  |          } | 
  | 87 | 0 |          fileWriter.append("<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\" SUMMARY=\"\">\n") | 
  | 88 |  |                  .append("<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n").append("<TD COLSPAN=") | 
  | 89 |  |                  .append(String.valueOf(colspan)).append("><FONT SIZE=\"+2\">\n").append("<B>").append(title) | 
  | 90 |  |                  .append("</B></FONT></TD>\n").append("</TR>\n"); | 
  | 91 |  |   | 
  | 92 | 0 |          for (List<String> row : cells) { | 
  | 93 | 0 |              fileWriter.append("<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">\n"); | 
  | 94 | 0 |              for (String cell : row) { | 
  | 95 | 0 |                  writeTD(fileWriter, cell); | 
  | 96 |  |              } | 
  | 97 | 0 |              fileWriter.append("</TR>\n"); | 
  | 98 |  |          } | 
  | 99 | 0 |          fileWriter.append("</TABLE>\n"); | 
  | 100 | 0 |      } | 
  | 101 |  |   | 
  | 102 |  |      private void writeTD(FileWriter fileWriter, String filePath) throws IOException { | 
  | 103 | 0 |          fileWriter.append("<TD VALIGN=\"top\">\n"); | 
  | 104 | 0 |          fileWriter.append(filePath); | 
  | 105 | 0 |          fileWriter.append("</TD>\n"); | 
  | 106 | 0 |      } | 
  | 107 |  |   | 
  | 108 |  |      private void writeHeader(Object object, FileWriter fileWriter) throws IOException { | 
  | 109 | 0 |          String title = createTitle(object); | 
  | 110 | 0 |          fileWriter.append("<head>").append("<title>").append(title).append("</title>") | 
  | 111 |  |                  .append("<LINK REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"../../stylesheet.css\" TITLE=\"Style\">") | 
  | 112 |  |                  .append("<SCRIPT type=\"text/javascript\">").append("function windowTitle()").append("{") | 
  | 113 |  |                  .append("    parent.document.title=\"").append(title.replaceAll("\"", "'")).append("\";").append("}") | 
  | 114 |  |                  .append("</SCRIPT>").append("</head>"); | 
  | 115 | 0 |      } | 
  | 116 |  |   | 
  | 117 |  |      protected abstract String createTitle(Object object); | 
  | 118 |  |   | 
  | 119 |  |      protected void writeChanges(String title, FileWriter fileWriter, List<Change> changes) throws IOException, | 
  | 120 |  |              DatabaseHistoryException, DatabaseException { | 
  | 121 | 0 |          fileWriter.append("<p><TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\" SUMMARY=\"\">\n"); | 
  | 122 | 0 |          fileWriter.append("<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n"); | 
  | 123 | 0 |          fileWriter.append("<TD COLSPAN='4'><FONT SIZE=\"+2\">\n"); | 
  | 124 | 0 |          fileWriter.append("<B>"); | 
  | 125 | 0 |          fileWriter.append(title); | 
  | 126 | 0 |          fileWriter.append("</B></FONT></TD>\n"); | 
  | 127 | 0 |          fileWriter.append("</TR>\n"); | 
  | 128 |  |   | 
  | 129 | 0 |          ChangeSet lastChangeSet = null; | 
  | 130 | 0 |          if (changes == null || changes.size() == 0) { | 
  | 131 | 0 |              fileWriter.append("<tr><td>None Found</td></tr>"); | 
  | 132 |  |          } else { | 
  | 133 | 0 |              for (Change change : changes) { | 
  | 134 | 0 |                  if (!change.getChangeSet().equals(lastChangeSet)) { | 
  | 135 | 0 |                      lastChangeSet = change.getChangeSet(); | 
  | 136 | 0 |                      fileWriter.append("<TR BGCOLOR=\"#EEEEFF\" CLASS=\"TableSubHeadingColor\">\n"); | 
  | 137 | 0 |                      writeTD(fileWriter, "<a href='../changelogs/" + change.getChangeSet().getFilePath() + ".xml'>" | 
  | 138 |  |                              + change.getChangeSet().getFilePath() + "</a>"); | 
  | 139 | 0 |                      writeTD(fileWriter, change.getChangeSet().getId()); | 
  | 140 | 0 |                      writeTD(fileWriter, "<a href='../authors/" + change.getChangeSet().getAuthor().toLowerCase() | 
  | 141 |  |                              + ".html'>" + change.getChangeSet().getAuthor().toLowerCase() + "</a>"); | 
  | 142 |  |   | 
  | 143 | 0 |                      ChangeSet.RunStatus runStatus = database.getRunStatus(change.getChangeSet()); | 
  | 144 | 0 |                      if (runStatus.equals(ChangeSet.RunStatus.NOT_RAN)) { | 
  | 145 | 0 |                          String anchor = change.getChangeSet().toString(false).replaceAll("\\W", "_"); | 
  | 146 | 0 |                          writeTD(fileWriter, "NOT YET RAN [<a href='../pending/sql.html#" + anchor + "'>SQL</a>]"); | 
  | 147 | 0 |                      } else if (runStatus.equals(ChangeSet.RunStatus.INVALID_MD5SUM)) { | 
  | 148 | 0 |                          writeTD(fileWriter, "INVALID MD5SUM"); | 
  | 149 | 0 |                      } else if (runStatus.equals(ChangeSet.RunStatus.ALREADY_RAN)) { | 
  | 150 | 0 |                          writeTD(fileWriter, | 
  | 151 |  |                                  "Executed " | 
  | 152 |  |                                          + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format( | 
  | 153 |  |                                                  database.getRanDate(change.getChangeSet()))); | 
  | 154 | 0 |                      } else if (runStatus.equals(ChangeSet.RunStatus.RUN_AGAIN)) { | 
  | 155 | 0 |                          writeTD(fileWriter, "Executed, WILL RUN AGAIN"); | 
  | 156 |  |                      } else { | 
  | 157 | 0 |                          throw new RuntimeException("Unknown run status: " + runStatus); | 
  | 158 |  |                      } | 
  | 159 |  |   | 
  | 160 | 0 |                      fileWriter.append("</TR>"); | 
  | 161 |  |   | 
  | 162 | 0 |                      if (StringUtils.trimToNull(change.getChangeSet().getComments()) != null) { | 
  | 163 | 0 |                          fileWriter.append("<TR><TD BGCOLOR='#EEEEFF' CLASS='TableSubHeadingColor' colspan='4'>") | 
  | 164 |  |                                  .append(change.getChangeSet().getComments()).append("</TD></TR>"); | 
  | 165 |  |                      } | 
  | 166 |  |   | 
  | 167 |  |                  } | 
  | 168 |  |   | 
  | 169 | 0 |                  fileWriter.append("<TR BGCOLOR=\"white\" CLASS=\"TableRowColor\">\n"); | 
  | 170 | 0 |                  fileWriter.append("<td colspan='4'>          ") | 
  | 171 |  |                          .append(change.getConfirmationMessage()).append("</td></TR>"); | 
  | 172 |  |              } | 
  | 173 |  |          } | 
  | 174 |  |   | 
  | 175 | 0 |          fileWriter.append("</TABLE>"); | 
  | 176 | 0 |          fileWriter.append(" </P>"); | 
  | 177 |  |   | 
  | 178 | 0 |      } | 
  | 179 |  |  } |