View Javadoc
1   /*
2    * This file is a part of the SchemaSpy project (http://schemaspy.sourceforge.net).
3    * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 John Currier
4    *
5    * SchemaSpy is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   * SchemaSpy is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18   */
19  package net.sourceforge.schemaspy.view;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.TreeSet;
29  import net.sourceforge.schemaspy.DbAnalyzer;
30  import net.sourceforge.schemaspy.model.Database;
31  import net.sourceforge.schemaspy.model.ForeignKeyConstraint;
32  import net.sourceforge.schemaspy.model.Table;
33  import net.sourceforge.schemaspy.model.TableColumn;
34  import net.sourceforge.schemaspy.util.HtmlEncoder;
35  import net.sourceforge.schemaspy.util.LineWriter;
36  
37  /**
38   * The page that lists all of the constraints in the schema
39   *
40   * @author John Currier
41   */
42  public class HtmlConstraintsPage extends HtmlFormatter {
43      private static HtmlConstraintsPage instance = new HtmlConstraintsPage();
44      private int columnCounter;
45  
46      /**
47       * Singleton: Don't allow instantiation
48       */
49      private HtmlConstraintsPage() {
50      }
51  
52      /**
53       * Singleton accessor
54       *
55       * @return the singleton instance
56       */
57      public static HtmlConstraintsPage getInstance() {
58          return instance;
59      }
60  
61      public void write(Database database, List<ForeignKeyConstraint> constraints, Collection<Table> tables, boolean hasOrphans, LineWriter html) throws IOException {
62          writeHeader(database, hasOrphans, html);
63          writeForeignKeyConstraints(constraints, html);
64          writeCheckConstraints(tables, html);
65          writeFooter(html);
66      }
67  
68      private void writeHeader(Database database, boolean hasOrphans, LineWriter html) throws IOException {
69          writeHeader(database, null, "Constraints", hasOrphans, html);
70          html.writeln("<div class='indent'>");
71      }
72  
73      @Override
74      protected void writeFooter(LineWriter html) throws IOException {
75          html.writeln("</div>");
76          super.writeFooter(html);
77      }
78  
79      /**
80       * Write specified foreign key constraints
81       *
82       * @param constraints List
83       * @param html LineWriter
84       * @throws IOException
85       */
86      private void writeForeignKeyConstraints(List<ForeignKeyConstraint> constraints, LineWriter html) throws IOException {
87          Set<ForeignKeyConstraint> constraintsByName = new TreeSet<ForeignKeyConstraint>();
88          constraintsByName.addAll(constraints);
89  
90          html.writeln("<table width='100%'>");
91          html.writeln("<tr><td class='container' valign='bottom'><b>");
92          html.write(String.valueOf(constraintsByName.size()));
93          html.writeln(" Foreign Key Constraints:</b>");
94          html.writeln("</td><td class='container' align='right'>");
95          html.writeln("<table>");
96          if (sourceForgeLogoEnabled())
97              html.writeln("  <tr><td class='container' align='right' valign='top'><a href='http://sourceforge.net' target='_blank'><img src='http://sourceforge.net/sflogo.php?group_id=137197&amp;type=1' alt='SourceForge.net' border='0' height='31' width='88'></a></td></tr>");
98          html.writeln("<tr><td class='container'>");
99          writeFeedMe(html);
100         html.writeln("</td></tr></table>");
101         html.writeln("</td></tr>");
102         html.writeln("</table><br>");
103         html.writeln("<table class='dataTable' border='1' rules='groups'>");
104         html.writeln("<colgroup>");
105         html.writeln("<colgroup>");
106         html.writeln("<colgroup>");
107         html.writeln("<colgroup>");
108         html.writeln("<thead align='left'>");
109         html.writeln("<tr>");
110         html.writeln("  <th>Constraint Name</th>");
111         html.writeln("  <th>Child Column</th>");
112         html.writeln("  <th>Parent Column</th>");
113         html.writeln("  <th>Delete Rule</th>");
114         html.writeln("</tr>");
115         html.writeln("</thead>");
116         html.writeln("<tbody>");
117         for (ForeignKeyConstraint constraint : constraintsByName) {
118             writeForeignKeyConstraint(constraint, html);
119         }
120         if (constraints.size() == 0) {
121             html.writeln(" <tr>");
122             html.writeln("  <td class='detail' valign='top' colspan='4'>None detected</td>");
123             html.writeln(" </tr>");
124         }
125         html.writeln("</tbody>");
126         html.writeln("</table>");
127     }
128 
129     /**
130      * Write specified foreign key constraint
131      *
132      * @param constraint ForeignKeyConstraint
133      * @param html LineWriter
134      * @throws IOException
135      */
136     private void writeForeignKeyConstraint(ForeignKeyConstraint constraint, LineWriter html) throws IOException {
137         boolean even = columnCounter++ % 2 == 0;
138         if (even)
139             html.writeln("  <tr class='even'>");
140         else
141             html.writeln("  <tr class='odd'>");
142         html.write("  <td class='detail'>");
143         html.write(constraint.getName());
144         html.writeln("</td>");
145         html.write("  <td class='detail'>");
146         for (Iterator<TableColumn> iter = constraint.getChildColumns().iterator(); iter.hasNext(); ) {
147             TableColumn column = iter.next();
148             html.write("<a href='tables/");
149             html.write(encodeHref(column.getTable().getName()));
150             html.write(".html'>");
151             html.write(column.getTable().getName());
152             html.write("</a>");
153             html.write(".");
154             html.write(column.getName());
155             if (iter.hasNext())
156                 html.write("<br>");
157         }
158         html.writeln("</td>");
159         html.write("  <td class='detail'>");
160         for (Iterator<TableColumn> iter = constraint.getParentColumns().iterator(); iter.hasNext(); ) {
161             TableColumn column = iter.next();
162             html.write("<a href='tables/");
163             html.write(encodeHref(column.getTable().getName()));
164             html.write(".html'>");
165             html.write(column.getTable().getName());
166             html.write("</a>");
167             html.write(".");
168             html.write(column.getName());
169             if (iter.hasNext())
170                 html.write("<br>");
171         }
172         html.writeln("</td>");
173         html.write("  <td class='detail'>");
174         String ruleText = constraint.getDeleteRuleDescription();
175         String ruleName = constraint.getDeleteRuleName();
176         html.write("<span title='" + ruleText + "'>" + ruleName + "&nbsp;</span>");
177         html.writeln("</td>");
178         html.writeln(" </tr>");
179     }
180 
181     /**
182      * Write check constraints associated with the specified tables
183      *
184      * @param tables Collection
185      * @param html LineWriter
186      * @throws IOException
187      */
188     public void writeCheckConstraints(Collection<Table> tables, LineWriter html) throws IOException {
189         html.writeln("<a name='checkConstraints'></a><p>");
190         html.writeln("<b>Check Constraints:</b>");
191         html.writeln("<TABLE class='dataTable' border='1' rules='groups'>");
192         html.writeln("<colgroup>");
193         html.writeln("<colgroup>");
194         html.writeln("<colgroup>");
195         html.writeln("<thead align='left'>");
196         html.writeln("<tr>");
197         html.writeln("  <th>Table</th>");
198         html.writeln("  <th>Constraint Name</th>");
199         html.writeln("  <th>Constraint</th>");
200         html.writeln("</tr>");
201         html.writeln("</thead>");
202         html.writeln("<tbody>");
203 
204         List<Table> tablesByName = DbAnalyzer.sortTablesByName(new ArrayList<Table>(tables));
205 
206         int constraintsWritten = 0;
207 
208         // iter over all tables...only ones with check constraints will write anything
209         for (Table table : tablesByName) {
210             constraintsWritten += writeCheckConstraints(table, html);
211         }
212 
213         if (constraintsWritten == 0) {
214             html.writeln(" <tr>");
215             html.writeln("  <td class='detail' valign='top' colspan='3'>None detected</td>");
216             html.writeln(" </tr>");
217         }
218 
219         html.writeln("</tbody>");
220         html.writeln("</table>");
221     }
222 
223     /**
224      * Write check constraints associated with the specified table (if any)
225      *
226      * @param table Table
227      * @param html LineWriter
228      * @throws IOException
229      * @return int
230      */
231     private int writeCheckConstraints(Table table, LineWriter html) throws IOException {
232         Map<String, String> constraints = table.getCheckConstraints();  // constraint name -> text pairs
233         int constraintsWritten = 0;
234         for (String name : constraints.keySet()) {
235             html.writeln(" <tr>");
236             html.write("  <td class='detail' valign='top'><a href='tables/");
237             html.write(encodeHref(table.getName()));
238             html.write(".html'>");
239             html.write(table.getName());
240             html.write("</a></td>");
241             html.write("  <td class='detail' valign='top'>");
242             html.write(name);
243             html.writeln("</td>");
244             html.write("  <td class='detail'>");
245             html.write(HtmlEncoder.encodeString(constraints.get(name).toString()));
246             html.writeln("</td>");
247             html.writeln(" </tr>");
248             ++constraintsWritten;
249         }
250 
251         return constraintsWritten;
252     }
253 
254     @Override
255     protected boolean isConstraintsPage() {
256         return true;
257     }
258 }