1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sourceforge.schemaspy;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.PrintStream;
26 import java.io.Reader;
27 import java.sql.DatabaseMetaData;
28 import java.sql.SQLException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import java.util.regex.Pattern;
36 import net.sourceforge.schemaspy.model.ProcessExecutionException;
37 import net.sourceforge.schemaspy.util.LineWriter;
38 import net.sourceforge.schemaspy.view.HtmlMultipleSchemasIndexPage;
39
40
41
42
43 public final class MultipleSchemaAnalyzer {
44 private static MultipleSchemaAnalyzer instance = new MultipleSchemaAnalyzer();
45 private final Logger logger = Logger.getLogger(getClass().getName());
46 private final boolean fineEnabled = logger.isLoggable(Level.FINE);
47
48 private MultipleSchemaAnalyzer() {
49 }
50
51 public static MultipleSchemaAnalyzer getInstance() {
52 return instance;
53 }
54
55 public void analyze(String dbName, DatabaseMetaData meta, String schemaSpec, List<String> schemas, List<String> args, String user, File outputDir, String charset, String loadedFrom) throws SQLException, IOException {
56 long start = System.currentTimeMillis();
57 List<String> genericCommand = new ArrayList<String>();
58 genericCommand.add("java");
59 genericCommand.add("-Doneofmultipleschemas=true");
60 if (new File(loadedFrom).isDirectory()) {
61 genericCommand.add("-cp");
62 genericCommand.add(loadedFrom);
63 genericCommand.add(Main.class.getName());
64 } else {
65 genericCommand.add("-jar");
66 genericCommand.add(loadedFrom);
67 }
68
69 for (String next : args) {
70 if (next.startsWith("-"))
71 genericCommand.add(next);
72 else
73 genericCommand.add("\"" + next + "\"");
74 }
75
76 List<String> populatedSchemas;
77 if (schemas == null) {
78 System.out.println("Analyzing schemas that match regular expression '" + schemaSpec + "':");
79 System.out.println("(use -schemaSpec on command line or in .properties to exclude other schemas)");
80 populatedSchemas = getPopulatedSchemas(meta, schemaSpec, user);
81 } else {
82 System.out.println("Analyzing schemas:");
83 populatedSchemas = schemas;
84 }
85
86 for (String populatedSchema : populatedSchemas)
87 System.out.print(" " + populatedSchema);
88 System.out.println();
89
90 writeIndexPage(dbName, populatedSchemas, meta, outputDir, charset);
91
92 for (String schema : populatedSchemas) {
93 List<String> command = new ArrayList<String>(genericCommand);
94 if (dbName == null)
95 command.add("-db");
96 else
97 command.add("-s");
98 command.add(schema);
99 command.add("-o");
100 command.add(new File(outputDir, schema).toString());
101 System.out.println("Analyzing " + schema);
102 System.out.flush();
103 Process java = Runtime.getRuntime().exec(command.toArray(new String[]{}));
104 new ProcessOutputReader(java.getInputStream(), System.out).start();
105 new ProcessOutputReader(java.getErrorStream(), System.err).start();
106
107 try {
108 int rc = java.waitFor();
109 if (rc != 0) {
110 StringBuilder err = new StringBuilder("Failed to execute this process (rc " + rc + "):");
111 for (String chunk : command) {
112 err.append(" ");
113 err.append(chunk);
114 }
115 throw new ProcessExecutionException(err.toString());
116 }
117 } catch (InterruptedException exc) {
118 }
119 }
120
121 long end = System.currentTimeMillis();
122 System.out.println();
123 System.out.println("Wrote relationship details of " + populatedSchemas.size() + " schema" + (populatedSchemas.size() == 1 ? "" : "s") + " in " + (end - start) / 1000 + " seconds.");
124 System.out.println("Start with " + new File(outputDir, "index.html"));
125 }
126
127 public void analyze(String dbName, List<String> schemas, List<String> args,
128 String user, File outputDir, String charset, String loadedFromJar) throws SQLException, IOException {
129 analyze(dbName, null, null, schemas, args, user, outputDir, charset, loadedFromJar);
130 }
131
132 private void writeIndexPage(String dbName, List<String> populatedSchemas, DatabaseMetaData meta, File outputDir, String charset) throws IOException {
133 if (populatedSchemas.size() > 0) {
134 LineWriter index = new LineWriter(new File(outputDir, "index.html"), charset);
135 HtmlMultipleSchemasIndexPage.getInstance().write(dbName, populatedSchemas, meta, index);
136 index.close();
137 }
138 }
139
140 private List<String> getPopulatedSchemas(DatabaseMetaData meta, String schemaSpec, String user) throws SQLException {
141 List<String> populatedSchemas;
142
143 if (meta.supportsSchemasInTableDefinitions()) {
144 Pattern schemaRegex = Pattern.compile(schemaSpec);
145
146 populatedSchemas = DbAnalyzer.getPopulatedSchemas(meta, schemaSpec);
147 Iterator<String> iter = populatedSchemas.iterator();
148 while (iter.hasNext()) {
149 String schema = iter.next();
150 if (!schemaRegex.matcher(schema).matches()) {
151 if (fineEnabled) {
152 logger.fine("Excluding schema " + schema +
153 ": doesn't match + \"" + schemaRegex + '"');
154 }
155 iter.remove();
156 } else {
157 if (fineEnabled) {
158 logger.fine("Including schema " + schema +
159 ": matches + \"" + schemaRegex + '"');
160 }
161 }
162 }
163 } else {
164 populatedSchemas = Arrays.asList(new String[] {user});
165 }
166
167 return populatedSchemas;
168 }
169
170 private static class ProcessOutputReader extends Thread {
171 private final Reader processReader;
172 private final PrintStream out;
173
174 ProcessOutputReader(InputStream processStream, PrintStream out) {
175 processReader = new InputStreamReader(processStream);
176 this.out = out;
177 setDaemon(true);
178 }
179
180 @Override
181 public void run() {
182 try {
183 int ch;
184 while ((ch = processReader.read()) != -1) {
185 out.print((char)ch);
186 out.flush();
187 }
188 } catch (IOException ioException) {
189 ioException.printStackTrace();
190 } finally {
191 try {
192 processReader.close();
193 } catch (Exception exc) {
194 exc.printStackTrace();
195 }
196 }
197 }
198 }
199 }