/**
   * Default constructor.
   *
   * @throws BuildException
   */
  public void execute() throws BuildException {
    log("Torque - JDBCToXMLSchema starting");
    log("Your DB settings are:");
    log("driver : " + dbDriver);
    log("URL : " + dbUrl);
    log("user : "******"password : "******"schema : " + dbSchema);

    DocumentTypeImpl docType = new DocumentTypeImpl(null, "database", null, "database.dtd");
    doc = new DocumentImpl(docType);
    doc.appendChild(doc.createComment(" Autogenerated by KualiTorqueJDBCTransformTask! "));

    try {
      generateXML();
      log(xmlSchema);
      OutputFormat of = new OutputFormat(Method.XML, null, true);
      of.setLineWidth(120);
      xmlSerializer = new XMLSerializer(new PrintWriter(new FileOutputStream(xmlSchema)), of);
      xmlSerializer.serialize(doc);
    } catch (Exception e) {
      throw new BuildException(e);
    }
    log("Torque - JDBCToXMLSchema finished");
  }
 /** @see org.w3c.dom.DOMImplementation */
 public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype)
     throws DOMException {
   if (doctype != null && doctype.getOwnerDocument() != null) {
     throw new DOMException(
         DOMException.WRONG_DOCUMENT_ERR,
         DOMMessageFormatter.formatMessage(
             DOMMessageFormatter.XML_DOMAIN, "WRONG_DOCUMENT_ERR", null));
   }
   DocumentImpl doc = new WMLDocumentImpl(doctype);
   // If namespaceURI and qualifiedName are null return a Document with no document element.
   if (qualifiedName != null || namespaceURI != null) {
     Element e = doc.createElementNS(namespaceURI, qualifiedName);
     doc.appendChild(e);
   }
   return doc;
 }
  /**
   * Generates an XML database schema from JDBC metadata.
   *
   * @throws Exception a generic exception.
   */
  public void generateXML() throws Exception {
    // Load the database Driver.
    Class.forName(dbDriver);
    log("DB driver sucessfuly instantiated");

    Connection con = null;
    try {
      // Attempt to connect to a database.
      Properties p = new Properties();
      p.setProperty("user", dbUser);
      p.setProperty("password", dbPassword);
      p.setProperty(
          "oracle.jdbc.mapDateToTimestamp", "false"); // workaround for change in 11g JDBC driver
      con = DriverManager.getConnection(dbUrl, p);
      log("DB connection established");

      Platform platform = PlatformFactory.getPlatformFor(dbType);

      // Get the database Metadata.
      DatabaseMetaData dbMetaData = con.getMetaData();

      databaseNode = doc.createElement("database");
      databaseNode.setAttribute("name", "kuali");
      // JHK added naming method
      databaseNode.setAttribute("defaultJavaNamingMethod", "nochange");

      if (processTables) {
        List<String> tableList = platform.getTableNames(dbMetaData, dbSchema);
        // ensure all are upper case before exporting
        tableList = upperCaseList(tableList);
        // ensure sorting is consistent (not DB-dependent)
        Collections.sort(tableList);
        for (String curTable : tableList) {
          if (!tableNameRegexPattern.matcher(curTable).matches()) {
            log("Skipping table: " + curTable);
            continue;
          }
          if (StringUtils.isNotBlank(tableNameExcludeRegex)
              && tableNameExcludeRegexPattern.matcher(curTable).matches()) {
            log("Skipping table: " + curTable);
            continue;
          }
          log("Processing table: " + curTable);

          Element table = doc.createElement("table");
          table.setAttribute("name", curTable.toUpperCase());

          // Add Columns.
          // TableMap tblMap = dbMap.getTable(curTable);

          List columns = getColumns(dbMetaData, curTable);
          List<String> primKeys = platform.getPrimaryKeys(dbMetaData, dbSchema, curTable);
          Map<String, Object[]> foreignKeys = getForeignKeys(dbMetaData, curTable);

          // Set the primary keys.
          primaryKeys = new HashMap<String, String>();

          for (int k = 0; k < primKeys.size(); k++) {
            String curPrimaryKey = (String) primKeys.get(k);
            primaryKeys.put(curPrimaryKey, curPrimaryKey);
          }

          for (int j = 0; j < columns.size(); j++) {
            List col = (List) columns.get(j);
            String name = (String) col.get(0);
            Integer jdbcType = ((Integer) col.get(1));
            int size = ((Integer) col.get(2)).intValue();
            int scale = ((Integer) col.get(5)).intValue();

            // From DatabaseMetaData.java
            //
            // Indicates column might not allow NULL values. Huh?
            // Might? Boy, that's a definitive answer.
            /* int columnNoNulls = 0; */

            // Indicates column definitely allows NULL values.
            /* int columnNullable = 1; */

            // Indicates NULLABILITY of column is unknown.
            /* int columnNullableUnknown = 2; */

            Integer nullType = (Integer) col.get(3);
            String defValue = (String) col.get(4);

            Element column = doc.createElement("column");
            column.setAttribute("name", name);

            ;
            column.setAttribute("type", platform.getTorqueColumnType(jdbcType));
            //							TypeMap.getTorqueType( type ).getName() );

            if (size > 0
                && (jdbcType.intValue() == Types.CHAR
                    || jdbcType.intValue() == Types.VARCHAR
                    || jdbcType.intValue() == Types.DECIMAL
                    || jdbcType.intValue() == Types.NUMERIC)) {
              column.setAttribute("size", String.valueOf(size));
            }

            if (scale > 0
                && (jdbcType.intValue() == Types.DECIMAL || jdbcType.intValue() == Types.NUMERIC)) {
              column.setAttribute("scale", String.valueOf(scale));
            }

            if (primaryKeys.containsKey(name)) {
              column.setAttribute("primaryKey", "true");
              // JHK: protect MySQL from excessively long column in the PK
              // System.out.println( curTable + "." + name + " / " + size );
              if (column.getAttribute("size") != null && size > 765) {
                log(
                    "updating column "
                        + curTable
                        + "."
                        + name
                        + " length from "
                        + size
                        + " to 255");
                column.setAttribute("size", "255");
              }
            } else {
              if (nullType.intValue() == DatabaseMetaData.columnNoNulls) {
                column.setAttribute("required", "true");
              }
            }

            if (StringUtils.isNotEmpty(defValue)) {
              defValue =
                  platform.getColumnDefaultValue(platform.getTorqueColumnType(jdbcType), defValue);
              if (StringUtils.isNotEmpty(defValue)) {
                column.setAttribute("default", defValue);
              }
            }
            table.appendChild(column);
          }

          List<String> foreignKeyNames = new ArrayList<String>(foreignKeys.keySet());
          Collections.sort(foreignKeyNames);
          // Foreign keys for this table.
          for (String fkName : foreignKeyNames) {
            Element fk = doc.createElement("foreign-key");
            fk.setAttribute("name", fkName.toUpperCase());
            Object[] forKey = foreignKeys.get(fkName);
            String foreignKeyTable = (String) forKey[0];
            List refs = (List) forKey[1];
            fk.setAttribute("foreignTable", foreignKeyTable.toUpperCase());
            String onDelete = (String) forKey[2];
            // gmcgrego - just adding onDelete if it's cascade so as not to affect kfs behavior
            if (onDelete == "cascade") {
              fk.setAttribute("onDelete", onDelete);
            }
            for (int m = 0; m < refs.size(); m++) {
              Element ref = doc.createElement("reference");
              String[] refData = (String[]) refs.get(m);
              ref.setAttribute("local", refData[0]);
              ref.setAttribute("foreign", refData[1]);
              fk.appendChild(ref);
            }
            table.appendChild(fk);
          }

          List<TableIndex> indexes = getIndexes(dbMetaData, curTable);
          Collections.sort(
              indexes,
              new Comparator<TableIndex>() {
                public int compare(TableIndex o1, TableIndex o2) {
                  return o1.name.compareTo(o2.name);
                }
              });
          for (TableIndex idx : indexes) {
            if (foreignKeyNames.contains(idx.name)) {
              log(idx.name + " is also a foreign key, skipping");
              continue;
            }
            String tagName = idx.unique ? "unique" : "index";
            Element index = doc.createElement(tagName);
            index.setAttribute("name", idx.name.toUpperCase());
            for (String colName : idx.columns) {
              Element col = doc.createElement(tagName + "-column");
              col.setAttribute("name", colName);
              index.appendChild(col);
            }
            table.appendChild(index);
          }

          databaseNode.appendChild(table);
        }
      }
      if (processViews) {
        log("Getting view list...");
        List<String> viewNames = platform.getViewNames(dbMetaData, dbSchema);
        log("Found " + viewNames.size() + " views.");
        viewNames = upperCaseList(viewNames);
        Collections.sort(viewNames);
        for (String viewName : viewNames) {
          if (!tableNameRegexPattern.matcher(viewName).matches()) {
            log("Skipping view: " + viewName);
            continue;
          }
          Element view = doc.createElement("view");
          view.setAttribute("name", viewName.toUpperCase());
          /*
           * <view name="" viewdefinition="" />
           *
           */
          String definition =
              platform.getViewDefinition(dbMetaData.getConnection(), dbSchema, viewName);
          definition = definition.replaceAll("\0", "");
          view.setAttribute("viewdefinition", definition);
          databaseNode.appendChild(view);
        }
      }

      if (processSequences) {
        log("Getting sequence list...");
        List<String> sequenceNames = platform.getSequenceNames(dbMetaData, dbSchema);
        log("Found " + sequenceNames.size() + " sequences.");
        sequenceNames = upperCaseList(sequenceNames);
        Collections.sort(sequenceNames);
        for (String sequenceName : sequenceNames) {
          if (!tableNameRegexPattern.matcher(sequenceName).matches()) {
            log("Skipping sequence: " + sequenceName);
            continue;
          }
          Element sequence = doc.createElement("sequence");
          sequence.setAttribute("name", sequenceName.toUpperCase());
          /*
           * <view name="" nextval="" />
           *
           */
          Long nextVal =
              platform.getSequenceNextVal(dbMetaData.getConnection(), dbSchema, sequenceName);
          sequence.setAttribute("nextval", nextVal.toString());

          databaseNode.appendChild(sequence);
        }
        doc.appendChild(databaseNode);
      }
    } finally {
      if (con != null) {
        con.close();
        con = null;
      }
    }
  }