/* * * SchemaCrawler * http://sourceforge.net/projects/schemacrawler * Copyright (c) 2000-2009, Sualeh Fatehi. * * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation; * either version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * */ package schemacrawler.tools.text.schema; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import schemacrawler.schema.Column; import schemacrawler.schema.ColumnDataType; import schemacrawler.schema.ColumnMap; import schemacrawler.schema.DatabaseInfo; import schemacrawler.schema.ForeignKey; import schemacrawler.schema.ForeignKeyColumnMap; import schemacrawler.schema.JdbcDriverInfo; import schemacrawler.schema.Procedure; import schemacrawler.schema.Schema; import schemacrawler.schema.SchemaCrawlerInfo; import schemacrawler.schema.Table; import schemacrawler.schema.View; import schemacrawler.schemacrawler.CrawlHandler; import schemacrawler.schemacrawler.SchemaCrawlerException; import schemacrawler.tools.text.util.HtmlFormattingHelper; import schemacrawler.tools.text.util.PastelColor; import schemacrawler.utility.MetaDataUtility; import schemacrawler.utility.MetaDataUtility.Connectivity; import sf.util.Utility; final class SchemaDotFormatter implements CrawlHandler { private static final Logger LOGGER = Logger .getLogger(SchemaDotFormatter.class.getName()); private static final String NEWLINE = System.getProperty("line.separator"); private final SchemaTextOptions options; private final PrintWriter out; private final Map<Schema, PastelColor> colorMap; private final StringBuilder graphInfo; /** * Text formatting of schema. * * @param options * Options for text formatting of schema */ SchemaDotFormatter(final SchemaTextOptions options) throws SchemaCrawlerException { if (options == null) { throw new IllegalArgumentException("Options not provided"); } this.options = options; out = options.getOutputOptions().openOutputWriter(); colorMap = new HashMap<Schema, PastelColor>(); graphInfo = new StringBuilder(); } public void begin() throws SchemaCrawlerException { final String text = Utility.readFully(HtmlFormattingHelper.class .getResourceAsStream("/dot.header.txt")); out.println(text); } public void end() throws SchemaCrawlerException { out.println("}"); out.flush(); // options.getOutputOptions().closeOutputWriter(out); LOGGER.log(Level.FINE, "Wrote output, " + options.getOutputOptions().getOutputFile()); } public void handle(final ColumnDataType dataType) throws SchemaCrawlerException { } public void handle(final ColumnMap[] weakAssociations) throws SchemaCrawlerException { if (weakAssociations == null) { return; } for (final ColumnMap columnMap: weakAssociations) { final Column primaryKeyColumn = columnMap.getPrimaryKeyColumn(); final Column foreignKeyColumn = columnMap.getForeignKeyColumn(); out.write(printColumnAssociation("", primaryKeyColumn, foreignKeyColumn)); } } public void handle(final DatabaseInfo databaseInfo) throws SchemaCrawlerException { graphInfo.append(" <tr>").append(NEWLINE); graphInfo.append(" <td align=\"right\">Database:</td>") .append(NEWLINE); graphInfo.append(" <td align=\"left\">" + databaseInfo.getProductName() + " " + databaseInfo.getProductVersion() + "</td>") .append(NEWLINE); graphInfo.append(" </tr>").append(NEWLINE); } public void handle(final JdbcDriverInfo jdbcDriverInfo) throws SchemaCrawlerException { graphInfo.append(" <tr>").append(NEWLINE); graphInfo.append(" <td align=\"right\">JDBC Connection:</td>") .append(NEWLINE); graphInfo.append(" <td align=\"left\">" + jdbcDriverInfo.getConnectionUrl() + "</td>") .append(NEWLINE); graphInfo.append(" </tr>").append(NEWLINE); graphInfo.append(" <tr>").append(NEWLINE); graphInfo.append(" <td align=\"right\">JDBC Driver:</td>") .append(NEWLINE); graphInfo.append(" <td align=\"left\">" + jdbcDriverInfo.getDriverName() + " " + jdbcDriverInfo.getDriverVersion() + "</td>") .append(NEWLINE); graphInfo.append(" </tr>").append(NEWLINE); graphInfo.append(" </table>"); final String graphLabel = String .format(" graph [%n label=<%n%s >%n labeljust=r%n labelloc=b%n ];%n%n", graphInfo.toString()); out.println(graphLabel); } public void handle(final Procedure procedure) throws SchemaCrawlerException { // No-op } public void handle(final SchemaCrawlerInfo schemaCrawlerInfo) throws SchemaCrawlerException { graphInfo .append(" <table border=\"1\" cellborder=\"0\" cellspacing=\"0\">") .append(NEWLINE); graphInfo.append(" <tr>").append(NEWLINE); graphInfo.append(" <td colspan=\"2\" align=\"left\">Generated by " + schemaCrawlerInfo.getSchemaCrawlerProductName() + " " + schemaCrawlerInfo.getSchemaCrawlerVersion() + "</td>") .append(NEWLINE); graphInfo.append(" </tr>").append(NEWLINE); } public void handle(final Table table) throws SchemaCrawlerException { final Schema schema = table.getSchema(); if (!colorMap.containsKey(schema)) { colorMap.put(schema, new PastelColor()); } final PastelColor bgcolor = colorMap.get(schema); final PastelColor tableBgColor = bgcolor.shade(); final StringBuilder buffer = new StringBuilder(); final String tableName = table.getFullName(); buffer.append(" \"" + tableName + "\" [").append(NEWLINE) .append(" label=<").append(NEWLINE); buffer .append(" <table border=\"1\" cellborder=\"0\" cellspacing=\"0\">") .append(NEWLINE); buffer.append(" <tr>").append(NEWLINE); buffer.append(" <td colspan=\"2\" bgcolor=\"" + tableBgColor + "\" align=\"left\">" + tableName + "</td>").append(NEWLINE); buffer.append(" <td bgcolor=\"" + tableBgColor + "\" align=\"right\">" + (table instanceof View? "[view]": "[table]") + "</td>") .append(NEWLINE); buffer.append(" </tr>").append(NEWLINE); for (final Column column: table.getColumns()) { final String columnName = column.getName(); final PastelColor columnBgcolor; if (column.isPartOfPrimaryKey()) { columnBgcolor = bgcolor; } else { columnBgcolor = bgcolor.tint(); } buffer.append(" <tr>").append(NEWLINE); buffer.append(" <td port=\"" + columnName + ".start\" bgcolor=\"" + columnBgcolor + "\" align=\"left\">" + columnName + "</td>") .append(NEWLINE); buffer.append(" <td bgcolor=\"" + columnBgcolor + "\"> </td>") .append(NEWLINE); buffer.append(" <td port=\"" + columnName + ".end\" align=\"right\" bgcolor=\"" + columnBgcolor + "\">" + column.getType().getDatabaseSpecificTypeName() + column.getWidth() + "</td>").append(NEWLINE); buffer.append(" </tr>").append(NEWLINE); } buffer.append(" </table>").append(NEWLINE); buffer.append(" >").append(NEWLINE).append(" ];").append(NEWLINE); for (final ForeignKey foreignKey: table.getForeignKeys()) { for (final ForeignKeyColumnMap foreignKeyColumnMap: foreignKey .getColumnPairs()) { final Column primaryKeyColumn = foreignKeyColumnMap .getPrimaryKeyColumn(); final Column foreignKeyColumn = foreignKeyColumnMap .getForeignKeyColumn(); if (primaryKeyColumn.getParent().equals(table)) { buffer.append(printColumnAssociation(foreignKey.getName(), primaryKeyColumn, foreignKeyColumn)); } } } buffer.append(NEWLINE).append(NEWLINE); out.write(buffer.toString()); } private String printColumnAssociation(final String associationName, final Column primaryKeyColumn, final Column foreignKeyColumn) { final Connectivity connectivity = MetaDataUtility .getConnectivity(foreignKeyColumn); final String pkSymbol = "teetee"; final String fkSymbol; if (connectivity != null) { switch (connectivity) { case OneToOne: fkSymbol = "teeodot"; break; case OneToMany: fkSymbol = "crowodot"; break; default: fkSymbol = "none"; break; } } else { fkSymbol = "none"; } final String style; if (Utility.isBlank(associationName)) { style = "dashed"; } else { style = "solid"; } return String .format(" \"%s\":\"%s.start\":w -> \"%s\":\"%s.end\":e [label=\"%s\" style=\"%s\" arrowhead=\"%s\" arrowtail=\"%s\"];%n", primaryKeyColumn.getParent().getFullName(), primaryKeyColumn.getName(), foreignKeyColumn.getParent().getFullName(), foreignKeyColumn.getName(), associationName, style, fkSymbol, pkSymbol); } }