/* * * SchemaCrawler * http://sourceforge.net/projects/schemacrawler * Copyright (c) 2000-2011, 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.util.logging.Level; import schemacrawler.schema.CheckConstraint; import schemacrawler.schema.Column; import schemacrawler.schema.ColumnDataType; import schemacrawler.schema.ColumnMap; import schemacrawler.schema.ConditionTimingType; import schemacrawler.schema.EventManipulationType; import schemacrawler.schema.ForeignKey; import schemacrawler.schema.ForeignKeyColumnMap; import schemacrawler.schema.ForeignKeyUpdateRule; import schemacrawler.schema.Index; import schemacrawler.schema.IndexColumn; import schemacrawler.schema.IndexType; import schemacrawler.schema.Privilege; import schemacrawler.schema.Privilege.Grant; import schemacrawler.schema.Procedure; import schemacrawler.schema.ProcedureColumn; import schemacrawler.schema.Table; import schemacrawler.schema.Trigger; import schemacrawler.schema.View; import schemacrawler.schemacrawler.SchemaCrawlerException; import schemacrawler.tools.analysis.associations.SimpleWeakAssociationsCollector; import schemacrawler.tools.options.OutputOptions; import schemacrawler.tools.text.base.BaseJsonFormatter; import schemacrawler.tools.text.utility.org.json.JSONArray; import schemacrawler.tools.text.utility.org.json.JSONException; import schemacrawler.tools.text.utility.org.json.JSONObject; import schemacrawler.tools.traversal.SchemaTraversalHandler; /** * Text formatting of schema. * * @author Sualeh Fatehi */ final class SchemaJsonFormatter extends BaseJsonFormatter<SchemaTextOptions> implements SchemaTraversalHandler { private final boolean isVerbose; private final boolean isNotList; /** * Text formatting of schema. * * @param schemaTextDetailType * Types for text formatting of schema * @param options * Options for text formatting of schema * @param outputOptions * Options for text formatting of schema * @throws SchemaCrawlerException * On an exception */ SchemaJsonFormatter(final SchemaTextDetailType schemaTextDetailType, final SchemaTextOptions options, final OutputOptions outputOptions) throws SchemaCrawlerException { super(options, schemaTextDetailType == SchemaTextDetailType.details, outputOptions); isVerbose = schemaTextDetailType .isGreaterThanOrEqualTo(SchemaTextDetailType.details); isNotList = schemaTextDetailType != SchemaTextDetailType.list; } @Override public void handle(final ColumnDataType columnDataType) throws SchemaCrawlerException { if (printVerboseDatabaseInfo && isVerbose) { try { final JSONObject jsonColumnDataType = new JSONObject(); jsonRoot.accumulate("columnDataypes", jsonColumnDataType); jsonColumnDataType.put("databaseSpecificTypeName", columnDataType.getDatabaseSpecificTypeName()); jsonColumnDataType .put("basedOn", columnDataType.getBaseType() == null? "" : columnDataType .getBaseType() .getName()); jsonColumnDataType.put("userDefined", columnDataType.isUserDefined()); jsonColumnDataType.put("createParameters", columnDataType.getCreateParameters()); jsonColumnDataType.put("nullable", columnDataType.isNullable()); jsonColumnDataType.put("autoIncrementable", columnDataType.isAutoIncrementable()); jsonColumnDataType.put("searchable", columnDataType.getSearchable() .toString()); } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting ColumnDataType: " + e.getMessage(), e); } } } /** * Provides information on the database schema. * * @param procedure * Procedure metadata. */ @Override public void handle(final Procedure procedure) { try { final JSONObject jsonProcedure = new JSONObject(); jsonRoot.accumulate("procedures", jsonProcedure); jsonProcedure.put("name", procedure.getName()); jsonProcedure.put("fullName", procedure.getFullName()); jsonProcedure.put("type", procedure.getType()); if (isNotList) { final JSONArray jsonParameters = new JSONArray(); jsonProcedure.put("parameters", jsonParameters); for (final ProcedureColumn column: procedure.getColumns()) { jsonParameters.put(handleProcedureColumn(column)); } jsonProcedure.put("definition", procedure.getDefinition()); if (isVerbose) { jsonProcedure.put("remarks", procedure.getRemarks()); } } } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting Procedure: " + e.getMessage(), e); } } /** * Provides information on the database schema. * * @param table * Table metadata. */ @Override public void handle(final Table table) { final JSONObject jsonTable = new JSONObject(); try { jsonRoot.accumulate("tables", jsonTable); jsonTable.put("name", table.getName()); jsonTable.put("fullName", table.getFullName()); jsonTable.put("type", table.getType()); if (isNotList) { final JSONArray jsonColumns = new JSONArray(); jsonTable.put("columns", jsonColumns); for (final Column column: table.getColumns()) { jsonColumns.put(handleTableColumn(column)); } jsonTable.put("primaryKey", handleIndex(table.getPrimaryKey())); jsonTable.put("foreignKeys", handleForeignKeys(table.getForeignKeys())); if (isVerbose) { final ColumnMap[] weakAssociations = SimpleWeakAssociationsCollector .getWeakAssociations(table); jsonTable .put("weakAssociations", handleColumnPairs(weakAssociations)); } final JSONArray jsonIndices = new JSONArray(); jsonTable.put("indices", jsonIndices); for (final Index index: table.getIndices()) { jsonIndices.put(handleIndex(index)); } if (isVerbose) { for (final CheckConstraint constraint: table.getCheckConstraints()) { if (constraint != null) { final JSONObject jsonConsraint = new JSONObject(); jsonTable.accumulate("constraints", jsonConsraint); jsonConsraint.put("name", constraint.getName()); jsonConsraint.put("definition", constraint.getDefinition()); } } for (final Privilege privilege: table.getPrivileges()) { if (privilege != null) { final JSONObject jsonPrivilege = new JSONObject(); jsonTable.accumulate("privileges", jsonPrivilege); jsonPrivilege.put("name", privilege.getName()); for (final Grant grant: privilege.getGrants()) { final JSONObject jsonGrant = new JSONObject(); jsonPrivilege.accumulate("grants", jsonGrant); jsonGrant.put("grantor", grant.getGrantor()); jsonGrant.put("grantee", grant.getGrantee()); jsonGrant.put("grantable", grant.isGrantable()); } } } final Trigger[] triggers = table.getTriggers(); jsonTable.put("triggers", handleTriggers(triggers)); } if (table instanceof View) { final View view = (View) table; jsonTable.put("definition", view.getDefinition()); } if (isVerbose) { jsonTable.put("remarks", table.getRemarks()); } } } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting Table: " + e.getMessage(), e); } } @Override public void handleColumnDataTypesEnd() { } @Override public void handleColumnDataTypesStart() { } @Override public void handleProceduresEnd() throws SchemaCrawlerException { } @Override public void handleProceduresStart() throws SchemaCrawlerException { } @Override public void handleTablesEnd() throws SchemaCrawlerException { } @Override public void handleTablesStart() throws SchemaCrawlerException { } private JSONArray handleColumnPairs(final ColumnMap... columnPairs) { final JSONArray jsonColumnPairs = new JSONArray(); for (final ColumnMap columnPair: columnPairs) { try { final JSONObject jsonColumnPair = new JSONObject(); jsonColumnPair.put("pkColumn", columnPair.getPrimaryKeyColumn()); jsonColumnPair.put("fkColumn", columnPair.getForeignKeyColumn()); if (columnPair instanceof ForeignKeyColumnMap && options.isShowOrdinalNumbers()) { final int keySequence = ((ForeignKeyColumnMap) columnPair) .getKeySequence(); jsonColumnPair.put("keySequence", keySequence); } jsonColumnPairs.put(jsonColumnPair); } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting ColumnMap: " + e.getMessage(), e); } } return jsonColumnPairs; } private JSONArray handleForeignKeys(final ForeignKey[] foreignKeys) { final JSONArray jsonFks = new JSONArray(); for (final ForeignKey foreignKey: foreignKeys) { if (foreignKey != null) { try { final JSONObject jsonFk = new JSONObject(); jsonFks.put(jsonFk); jsonFk.put("name", foreignKey.getName()); final ForeignKeyUpdateRule updateRule = foreignKey.getUpdateRule(); if (updateRule != null && updateRule != ForeignKeyUpdateRule.unknown) { jsonFk.put("updateRule", updateRule.toString()); } final ForeignKeyUpdateRule deleteRule = foreignKey.getDeleteRule(); if (deleteRule != null && deleteRule != ForeignKeyUpdateRule.unknown) { jsonFk.put("deleteRule", deleteRule.toString()); } final ForeignKeyColumnMap[] columnPairs = foreignKey.getColumnPairs(); jsonFk.put("columnPairs", handleColumnPairs(columnPairs)); } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting ForeignKey: " + e.getMessage(), e); } } } return jsonFks; } private JSONObject handleIndex(final Index index) { final JSONObject jsonIndex = new JSONObject(); if (index == null) { return jsonIndex; } try { jsonIndex.put("name", index.getName()); final IndexType indexType = index.getType(); if (indexType != IndexType.unknown && indexType != IndexType.other) { jsonIndex.put("type", indexType.toString()); } jsonIndex.put("unique", index.isUnique()); final IndexColumn[] columns = index.getColumns(); for (final IndexColumn indexColumn: columns) { jsonIndex.accumulate("columns", handleTableColumn(indexColumn)); } } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting Index: " + e.getMessage(), e); } return jsonIndex; } private JSONObject handleProcedureColumn(final ProcedureColumn column) { final JSONObject jsonColumn = new JSONObject(); try { jsonColumn.put("dataType", column.getType().getTypeName()); jsonColumn.put("databaseSpecificType", column.getType() .getDatabaseSpecificTypeName()); jsonColumn.put("width", column.getWidth()); jsonColumn.put("type", column.getProcedureColumnType().toString()); jsonColumn.put("ordinal", column.getOrdinalPosition() + 1); } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting ProcedureColumn: " + e.getMessage(), e); } return jsonColumn; } private JSONObject handleTableColumn(final Column column) { final JSONObject jsonColumn = new JSONObject(); try { jsonColumn.put("name", column.getName()); if (column instanceof IndexColumn) { jsonColumn.put("sortSequence", ((IndexColumn) column).getSortSequence() .name()); } else { jsonColumn.put("dataType", column.getType().getTypeName()); jsonColumn.put("databaseSpecificType", column.getType() .getDatabaseSpecificTypeName()); jsonColumn.put("width", column.getWidth()); jsonColumn.put("size", column.getSize()); jsonColumn.put("decimalDigits", column.getDecimalDigits()); jsonColumn.put("nullable", column.isNullable()); } jsonColumn.put("ordinal", column.getOrdinalPosition()); if (isVerbose) { jsonColumn.put("remarks", column.getRemarks()); } } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting Column: " + e.getMessage(), e); } return jsonColumn; } private JSONArray handleTriggers(final Trigger[] triggers) { final JSONArray jsonTriggers = new JSONArray(); for (final Trigger trigger: triggers) { if (trigger != null) { try { final JSONObject jsonTrigger = new JSONObject(); jsonTriggers.put(jsonTrigger); final ConditionTimingType conditionTiming = trigger .getConditionTiming(); final EventManipulationType eventManipulationType = trigger .getEventManipulationType(); if (conditionTiming != null && conditionTiming != ConditionTimingType.unknown && eventManipulationType != null && eventManipulationType != EventManipulationType.unknown) { jsonTrigger.put("conditionTiming", conditionTiming); jsonTrigger.put("eventManipulationType", eventManipulationType); } jsonTrigger.put("actionOrientation", trigger.getActionOrientation()); jsonTrigger.put("actionCondition", trigger.getActionCondition()); jsonTrigger.put("actionStatement", trigger.getActionStatement()); } catch (final JSONException e) { LOGGER.log(Level.FINER, "Error outputting Trigger: " + e.getMessage(), e); } } } return jsonTriggers; } }