startGraphing = System.currentTimeMillis(); System.out.println("(" + (startGraphing - startSummarizing) / 1000 + "sec)");
startGraphingDetails = System.currentTimeMillis(); System.out.println("(" + (startGraphingDetails - startSummarizing) / 1000 + "sec)");
    public static void main(String[] argv) {        try {            List args = new ArrayList(Arrays.asList(argv)); // can't mod the original            if (args.size() == 0 || args.remove("-h") || args.remove("-?") || args.remove("?") || args.remove("/?")) {                dumpUsage(null, false, false);                System.exit(1);            }            if (args.remove("-help")) {                dumpUsage(null, true, false);                System.exit(1);            }            if (args.remove("-dbhelp")) {                dumpUsage(null, true, true);                System.exit(1);            }            long start = System.currentTimeMillis();            long startGraphing = start;            long startSummarizing = start;            // allow '=' in param specs            args = fixupArgs(args);            final boolean generateHtml = !args.remove("-nohtml");            final boolean includeImpliedConstraints = !args.remove("-noimplied");            File outputDir = new File(getParam(args, "-o", true, false));            if (!outputDir.isDirectory()) {                if (!outputDir.mkdir()) {                    System.err.println("Failed to create directory '" + outputDir + "'");                    System.exit(2);                }            }            if (generateHtml) {                new File(outputDir, "tables").mkdir();                new File(outputDir, "graphs/summary").mkdirs();            }            String dbType = getParam(args, "-t", false, false);            if (dbType == null)                dbType = "ora";            StringBuffer propertiesLoadedFrom = new StringBuffer();            Properties properties = getDbProperties(dbType, propertiesLoadedFrom);            String user = getParam(args, "-u", true, false);            String password = getParam(args, "-p", false, false);            String schema = null;            try {                schema = getParam(args, "-s", false, true);            } catch (Exception schemaNotSpecified) {            }            String classpath = getParam(args, "-cp", false, false);            String css = getParam(args, "-css", false, false);            if (css == null)                css = "schemaSpy.css";            int maxDbThreads = getMaxDbThreads(args, properties);            if (!args.remove("-nologo")) {                // nasty hack, but passing this info everywhere churns my stomach                System.setProperty("sourceforgelogo", "true");            }            ConnectionURLBuilder urlBuilder = null;            try {                urlBuilder = new ConnectionURLBuilder(dbType, args, properties);            } catch (IllegalArgumentException badParam) {                System.err.println(badParam.getMessage());                System.exit(1);            }            String dbName = urlBuilder.getDbName();            if (args.size() != 0) {                System.out.print("Warning: Unrecognized option(s):");                for (Iterator iter = args.iterator(); iter.hasNext(); ) {                    System.out.print(" " + iter.next());                }                System.out.println();            }            if (generateHtml)                StyleSheet.init(new BufferedReader(getStyleSheet(css)));            String driverClass = properties.getProperty("driver");            String driverPath = properties.getProperty("driverPath");            if (classpath != null)                driverPath = classpath + File.pathSeparator + driverPath;            Connection connection = getConnection(user, password, urlBuilder.getConnectionURL(), driverClass, driverPath, propertiesLoadedFrom.toString());            DatabaseMetaData meta = connection.getMetaData();            if (schema == null && meta.supportsSchemasInTableDefinitions()) {                schema = user;            }            if (generateHtml) {                System.out.println("Connected to " + meta.getDatabaseProductName() + " - " + meta.getDatabaseProductVersion());                System.out.println();                System.out.print("Gathering schema details");            }            //            // create the spy            //            SchemaSpy spy = new SchemaSpy(connection, meta, dbName, schema, properties, maxDbThreads);            Database db = spy.getDatabase();            LineWriter out;            Collection tables = new ArrayList(db.getTables());            tables.addAll(db.getViews());            if (tables.isEmpty()) {                dumpNoTablesMessage(schema, user, meta);                System.exit(2);            }            if (generateHtml) {                startSummarizing = System.currentTimeMillis();                System.out.println("(" + (startSummarizing - start) / 1000 + "sec)");                System.out.print("Writing/graphing summary");                System.out.print(".");                File graphsDir = new File(outputDir, "graphs/summary");                String dotBaseFilespec = "relationships";                out = new LineWriter(new FileWriter(new File(graphsDir, dotBaseFilespec + ".real.dot")));                int numRelationships =  new DotFormatter().writeRelationships(tables, false, out);                boolean hasRelationships = numRelationships > 0;                out.close();                // getting implied constraints has a side-effect of associating the parent/child tables, so don't do it                // here unless they want that behavior                List impliedConstraints = null;                if (includeImpliedConstraints)                    impliedConstraints = DBAnalyzer.getImpliedConstraints(tables);                else                    impliedConstraints = new ArrayList();                List orphans = DBAnalyzer.getOrphans(tables);                boolean hasOrphans = !orphans.isEmpty();                if (hasRelationships) {                    System.out.print(".");                    File impliedDotFile = new File(graphsDir, dotBaseFilespec + ".implied.dot");                    out = new LineWriter(new FileWriter(impliedDotFile));                    int numImplied = new DotFormatter().writeRelationships(tables, true, out) - numRelationships;                    out.close();                    boolean hasImplied = numImplied != 0;                    if (!hasImplied)                        impliedDotFile.delete();                    out = new LineWriter(new FileWriter(new File(outputDir, dotBaseFilespec + ".html")));                    hasRelationships = new HtmlGraphFormatter().write(db, graphsDir, dotBaseFilespec, hasOrphans, hasImplied, out);                    out.close();                }                System.out.print(".");                dotBaseFilespec = "utilities";                out = new LineWriter(new FileWriter(new File(outputDir, dotBaseFilespec + ".html")));                hasOrphans = new HtmlGraphFormatter().writeOrphans(db, orphans, hasRelationships, graphsDir, out);                out.close();                System.out.print(".");                out = new LineWriter(new FileWriter(new File(outputDir, "index.html")), 64 * 1024);                HtmlMainIndexFormatter indexFormatter = new HtmlMainIndexFormatter();                indexFormatter.write(db, tables, hasRelationships, hasOrphans, out);                out.close();                System.out.print(".");                List constraints = DBAnalyzer.getForeignKeyConstraints(tables);                out = new LineWriter(new FileWriter(new File(outputDir, "constraints.html")), 256 * 1024);                HtmlConstraintIndexFormatter constraintIndexFormatter = new HtmlConstraintIndexFormatter();                constraintIndexFormatter.write(db, constraints, tables, hasRelationships, hasOrphans, out);                out.close();                System.out.print(".");                out = new LineWriter(new FileWriter(new File(outputDir, "anomalies.html")), 16 * 1024);                HtmlAnomaliesFormatter anomaliesFormatter = new HtmlAnomaliesFormatter();                anomaliesFormatter.write(db, tables, impliedConstraints, hasRelationships, hasOrphans, out);                out.close();                startGraphing = System.currentTimeMillis();                System.out.println("(" + (startGraphing - startSummarizing) / 1000 + "sec)");                System.out.print("Writing/graphing results");                HtmlTableFormatter tableFormatter = new HtmlTableFormatter();                for (Iterator iter = tables.iterator(); iter.hasNext(); ) {                    System.out.print('.');                    Table table = (Table)iter.next();                    out = new LineWriter(new FileWriter(new File(outputDir, "tables/" + table.getName() + ".html")), 24 * 1024);                    tableFormatter.write(db, table, hasRelationships, hasOrphans, outputDir, out);                    out.close();                }                out = new LineWriter(new FileWriter(new File(outputDir, "schemaSpy.css")));                StyleSheet.write(out);                out.close();                out = new LineWriter(new FileWriter(new File(outputDir, "schemaSpy.js")));                JavaScriptFormatter.write(out);                out.close();            }            List recursiveConstraints = new ArrayList();            // side effect is that the RI relationships get trashed            // also populates the recursiveConstraints collection            List orderedTables = spy.sortTablesByRI(recursiveConstraints);            out = new LineWriter(new FileWriter(new File(outputDir, "insertionOrder.txt")), 16 * 1024);            new TextFormatter().write(db, orderedTables, false, out);            out.close();            out = new LineWriter(new FileWriter(new File(outputDir, "deletionOrder.txt")), 16 * 1024);            Collections.reverse(orderedTables);            new TextFormatter().write(db, orderedTables, false, out);            out.close();//            File constraintsFile = new File(outputDir, "removeRecursiveConstraints.sql");//            constraintsFile.delete();//            if (!recursiveConstraints.isEmpty()) {//                out = new LineWriter(new FileWriter(constraintsFile), 4 * 1024);//                writeRemoveRecursiveConstraintsSql(recursiveConstraints, schema, out);//                out.close();//            }////            constraintsFile = new File(outputDir, "restoreRecursiveConstraints.sql");//            constraintsFile.delete();////            if (!recursiveConstraints.isEmpty()) {//                out = new LineWriter(new FileWriter(constraintsFile), 4 * 1024);//                writeRestoreRecursiveConstraintsSql(recursiveConstraints, schema, out);//                out.close();//            }            if (generateHtml) {                long end = System.currentTimeMillis();                System.out.println("(" + (end - startSummarizing) / 1000 + "sec)");                System.out.println("Wrote relationship details of " + tables.size() + " tables/views to directory '" + outputDir + "' in " + (end - start) / 1000 + " seconds.");                System.out.println("Start with " + new File(outputDir, "index.html"));            }        } catch (IllegalArgumentException badParam) {            System.err.println();            badParam.printStackTrace();            dumpUsage(badParam.getMessage(), false, false);        } catch (Exception exc) {            System.err.println();            exc.printStackTrace();        }    }