| 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 | |
} |