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.beans.BeanInfo;
22 import java.beans.IntrospectionException;
23 import java.beans.Introspector;
24 import java.beans.PropertyDescriptor;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.net.URLDecoder;
34 import java.sql.DatabaseMetaData;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Enumeration;
38 import java.util.HashMap;
39 import java.util.LinkedHashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Map.Entry;
43 import java.util.Properties;
44 import java.util.PropertyResourceBundle;
45 import java.util.ResourceBundle;
46 import java.util.Set;
47 import java.util.StringTokenizer;
48 import java.util.TreeSet;
49 import java.util.jar.JarEntry;
50 import java.util.jar.JarInputStream;
51 import java.util.logging.Level;
52 import java.util.regex.Pattern;
53 import java.util.regex.PatternSyntaxException;
54 import net.sourceforge.schemaspy.model.InvalidConfigurationException;
55 import net.sourceforge.schemaspy.util.DbSpecificConfig;
56 import net.sourceforge.schemaspy.util.Dot;
57 import net.sourceforge.schemaspy.view.DefaultSqlFormatter;
58 import net.sourceforge.schemaspy.view.SqlFormatter;
59
60
61
62
63
64
65 public class Config
66 {
67 private static Config instance;
68 private final List<String> options;
69 private Map<String, String> dbSpecificOptions;
70 private Map<String, String> originalDbSpecificOptions;
71 private boolean helpRequired;
72 private boolean dbHelpRequired;
73 private File outputDir;
74 private File graphvizDir;
75 private String dbType;
76 private String schema;
77 private List<String> schemas;
78 private String user;
79 private Boolean singleSignOn;
80 private Boolean noSchema;
81 private String password;
82 private Boolean promptForPassword;
83 private String db;
84 private String host;
85 private Integer port;
86 private String server;
87 private String meta;
88 private Pattern tableInclusions;
89 private Pattern tableExclusions;
90 private Pattern columnExclusions;
91 private Pattern indirectColumnExclusions;
92 private String userConnectionPropertiesFile;
93 private Properties userConnectionProperties;
94 private Integer maxDbThreads;
95 private Integer maxDetailedTables;
96 private String driverPath;
97 private String css;
98 private String charset;
99 private String font;
100 private Integer fontSize;
101 private String description;
102 private String dbPropertiesLoadedFrom;
103 private Level logLevel;
104 private SqlFormatter sqlFormatter;
105 private String sqlFormatterClass;
106 private Boolean generateHtml;
107 private Boolean includeImpliedConstraints;
108 private Boolean logoEnabled;
109 private Boolean rankDirBugEnabled;
110 private Boolean encodeCommentsEnabled;
111 private Boolean numRowsEnabled;
112 private Boolean viewsEnabled;
113 private Boolean meterEnabled;
114 private Boolean railsEnabled;
115 private Boolean evaluteAll;
116 private Boolean highQuality;
117 private Boolean lowQuality;
118 private Boolean adsEnabled;
119 private String schemaSpec;
120 private boolean populating = false;
121 public static final String DOT_CHARSET = "UTF-8";
122 private static final String ESCAPED_EQUALS = "\\=";
123
124
125
126
127
128 public Config()
129 {
130 if (instance == null)
131 setInstance(this);
132 options = new ArrayList<String>();
133 }
134
135
136
137
138
139
140 public Config(String[] argv)
141 {
142 setInstance(this);
143 options = fixupArgs(Arrays.asList(argv));
144
145 helpRequired = options.remove("-?") ||
146 options.remove("/?") ||
147 options.remove("?") ||
148 options.remove("-h") ||
149 options.remove("-help") ||
150 options.remove("--help");
151 dbHelpRequired = options.remove("-dbHelp") || options.remove("-dbhelp");
152 }
153
154 public static Config getInstance() {
155 if (instance == null)
156 instance = new Config();
157
158 return instance;
159 }
160
161
162
163
164
165
166
167 public static void setInstance(Config config) {
168 instance = config;
169 }
170
171 public void setHtmlGenerationEnabled(boolean generateHtml) {
172 this.generateHtml = generateHtml;
173 }
174
175 public boolean isHtmlGenerationEnabled() {
176 if (generateHtml == null)
177 generateHtml = !options.remove("-nohtml");
178
179 return generateHtml;
180 }
181
182 public void setImpliedConstraintsEnabled(boolean includeImpliedConstraints) {
183 this.includeImpliedConstraints = includeImpliedConstraints;
184 }
185
186 public boolean isImpliedConstraintsEnabled() {
187 if (includeImpliedConstraints == null)
188 includeImpliedConstraints = !options.remove("-noimplied");
189
190 return includeImpliedConstraints;
191 }
192
193 public void setOutputDir(String outputDirName) {
194 if (outputDirName.endsWith("\""))
195 outputDirName = outputDirName.substring(0, outputDirName.length() - 1);
196
197 setOutputDir(new File(outputDirName));
198 }
199
200 public void setOutputDir(File outputDir) {
201 this.outputDir = outputDir;
202 }
203
204 public File getOutputDir() {
205 if (outputDir == null) {
206 setOutputDir(pullRequiredParam("-o"));
207 }
208
209 return outputDir;
210 }
211
212
213
214
215
216 public void setGraphvizDir(String graphvizDir) {
217 if (graphvizDir.endsWith("\""))
218 graphvizDir = graphvizDir.substring(0, graphvizDir.length() - 1);
219
220 setGraphvizDir(new File(graphvizDir));
221 }
222
223
224
225
226 public void setGraphvizDir(File graphvizDir) {
227 this.graphvizDir = graphvizDir;
228 }
229
230
231
232
233
234
235
236
237
238 public File getGraphvizDir() {
239 if (graphvizDir == null) {
240 String gv = pullParam("-gv");
241 if (gv != null) {
242 setGraphvizDir(gv);
243 } else {
244
245 }
246 }
247
248 return graphvizDir;
249 }
250
251
252
253
254
255
256
257
258
259
260 public void setMeta(String meta) {
261 this.meta = meta;
262 }
263
264 public String getMeta() {
265 if (meta == null)
266 meta = pullParam("-meta");
267 return meta;
268 }
269
270 public void setDbType(String dbType) {
271 this.dbType = dbType;
272 }
273
274 public String getDbType() {
275 if (dbType == null) {
276 dbType = pullParam("-t");
277 if (dbType == null)
278 dbType = "ora";
279 }
280
281 return dbType;
282 }
283
284 public void setDb(String db) {
285 this.db = db;
286 }
287
288 public String getDb() {
289 if (db == null)
290 db = pullParam("-db");
291 return db;
292 }
293
294 public void setSchema(String schema) {
295 this.schema = schema;
296 }
297
298 public String getSchema() {
299 if (schema == null)
300 schema = pullParam("-s");
301 return schema;
302 }
303
304
305
306
307
308
309
310
311 public boolean isSchemaDisabled() {
312 if (noSchema == null)
313 noSchema = options.remove("-noschema");
314
315 return noSchema;
316 }
317
318 public void setHost(String host) {
319 this.host = host;
320 }
321
322 public String getHost() {
323 if (host == null)
324 host = pullParam("-host");
325 return host;
326 }
327
328 public void setPort(Integer port) {
329 this.port = port;
330 }
331
332 public Integer getPort() {
333 if (port == null)
334 try {
335 port = Integer.valueOf(pullParam("-port"));
336 } catch (Exception notSpecified) {}
337 return port;
338 }
339
340 public void setServer(String server) {
341 this.server = server;
342 }
343
344 public String getServer() {
345 if (server == null) {
346 server = pullParam("-server");
347 }
348
349 return server;
350 }
351
352 public void setUser(String user) {
353 this.user = user;
354 }
355
356
357
358
359
360
361
362 public String getUser() {
363 if (user == null) {
364 if (!isSingleSignOn())
365 user = pullRequiredParam("-u");
366 else
367 user = pullParam("-u");
368 }
369 return user;
370 }
371
372
373
374
375
376
377
378
379 public void setSingleSignOn(boolean enabled) {
380 singleSignOn = enabled;
381 }
382
383
384
385
386 public boolean isSingleSignOn() {
387 if (singleSignOn == null)
388 singleSignOn = options.remove("-sso");
389
390 return singleSignOn;
391 }
392
393
394
395
396
397 public void setPassword(String password) {
398 this.password = password;
399 }
400
401
402
403
404
405 public String getPassword() {
406 if (password == null)
407 password = pullParam("-p");
408 return password;
409 }
410
411
412
413
414
415 public void setPromptForPasswordEnabled(boolean promptForPassword) {
416 this.promptForPassword = promptForPassword;
417 }
418
419
420
421
422
423 public boolean isPromptForPasswordEnabled() {
424 if (promptForPassword == null) {
425 promptForPassword = options.remove("-pfp");
426 }
427
428 return promptForPassword;
429 }
430
431 public void setMaxDetailedTabled(int maxDetailedTables) {
432 this.maxDetailedTables = new Integer(maxDetailedTables);
433 }
434
435 public int getMaxDetailedTables() {
436 if (maxDetailedTables == null) {
437 int max = 300;
438 try {
439 max = Integer.parseInt(pullParam("-maxdet"));
440 } catch (Exception notSpecified) {}
441
442 maxDetailedTables = new Integer(max);
443 }
444
445 return maxDetailedTables.intValue();
446 }
447
448 public String getConnectionPropertiesFile() {
449 return userConnectionPropertiesFile;
450 }
451
452
453
454
455
456
457
458
459
460
461 public void setConnectionPropertiesFile(String propertiesFilename) throws FileNotFoundException, IOException {
462 if (userConnectionProperties == null)
463 userConnectionProperties = new Properties();
464 userConnectionProperties.load(new FileInputStream(propertiesFilename));
465 userConnectionPropertiesFile = propertiesFilename;
466 }
467
468
469
470
471
472
473
474
475
476 public Properties getConnectionProperties() throws FileNotFoundException, IOException {
477 if (userConnectionProperties == null) {
478 String props = pullParam("-connprops");
479 if (props != null) {
480 if (props.indexOf(ESCAPED_EQUALS) != -1) {
481 setConnectionProperties(props);
482 } else {
483 setConnectionPropertiesFile(props);
484 }
485 } else {
486 userConnectionProperties = new Properties();
487 }
488 }
489
490 return userConnectionProperties;
491 }
492
493
494
495
496
497
498
499
500
501
502
503 public void setConnectionProperties(String properties) {
504 userConnectionProperties = new Properties();
505
506 StringTokenizer tokenizer = new StringTokenizer(properties, ";");
507 while (tokenizer.hasMoreElements()) {
508 String pair = tokenizer.nextToken();
509 int index = pair.indexOf(ESCAPED_EQUALS);
510 if (index != -1) {
511 String key = pair.substring(0, index);
512 String value = pair.substring(index + ESCAPED_EQUALS.length());
513 userConnectionProperties.put(key, value);
514 }
515 }
516 }
517
518 public void setDriverPath(String driverPath) {
519 this.driverPath = driverPath;
520 }
521
522 public String getDriverPath() {
523 if (driverPath == null)
524 driverPath = pullParam("-dp");
525
526
527 if (driverPath == null)
528 driverPath = pullParam("-cp");
529
530 return driverPath;
531 }
532
533
534
535
536
537
538
539
540
541
542
543 public void setCss(String css) {
544 this.css = css;
545 }
546
547 public String getCss() {
548 if (css == null) {
549 css = pullParam("-css");
550 if (css == null)
551 css = "schemaSpy.css";
552 }
553 return css;
554 }
555
556
557
558
559
560
561 public void setFont(String font) {
562 this.font = font;
563 }
564
565
566
567
568 public String getFont() {
569 if (font == null) {
570 font = pullParam("-font");
571 if (font == null)
572 font = "Helvetica";
573 }
574 return font;
575 }
576
577
578
579
580
581
582
583
584
585
586
587 public void setFontSize(int fontSize) {
588 this.fontSize = new Integer(fontSize);
589 }
590
591
592
593
594
595 public int getFontSize() {
596 if (fontSize == null) {
597 int size = 11;
598 try {
599 size = Integer.parseInt(pullParam("-fontsize"));
600 } catch (Exception notSpecified) {}
601
602 fontSize = new Integer(size);
603 }
604
605 return fontSize.intValue();
606 }
607
608
609
610
611
612
613 public void setCharset(String charset) {
614 this.charset = charset;
615 }
616
617
618
619
620 public String getCharset() {
621 if (charset == null) {
622 charset = pullParam("-charset");
623 if (charset == null)
624 charset = "ISO-8859-1";
625 }
626 return charset;
627 }
628
629
630
631
632
633
634 public void setDescription(String description) {
635 this.description = description;
636 }
637
638
639
640
641 public String getDescription() {
642 if (description == null)
643 description = pullParam("-desc");
644 return description;
645 }
646
647
648
649
650
651
652 public void setMaxDbThreads(int maxDbThreads) {
653 this.maxDbThreads = new Integer(maxDbThreads);
654 }
655
656
657
658
659
660 public int getMaxDbThreads() throws InvalidConfigurationException {
661 if (maxDbThreads == null) {
662 Properties properties;
663 try {
664 properties = getDbProperties(getDbType());
665 } catch (IOException exc) {
666 throw new InvalidConfigurationException("Failed to load properties for " + getDbType() + ": " + exc)
667 .setParamName("-type");
668 }
669
670 int max = Integer.MAX_VALUE;
671 String threads = properties.getProperty("dbThreads");
672 if (threads == null)
673 threads = properties.getProperty("dbthreads");
674 if (threads != null)
675 max = Integer.parseInt(threads);
676 threads = pullParam("-dbThreads");
677 if (threads == null)
678 threads = pullParam("-dbthreads");
679 if (threads != null)
680 max = Integer.parseInt(threads);
681 if (max < 0)
682 max = Integer.MAX_VALUE;
683 else if (max == 0)
684 max = 1;
685
686 maxDbThreads = new Integer(max);
687 }
688
689 return maxDbThreads.intValue();
690 }
691
692 public boolean isLogoEnabled() {
693 if (logoEnabled == null)
694 logoEnabled = !options.remove("-nologo");
695
696 return logoEnabled;
697 }
698
699
700
701
702
703
704 public void setRankDirBugEnabled(boolean enabled) {
705 rankDirBugEnabled = enabled;
706 }
707
708
709
710
711 public boolean isRankDirBugEnabled() {
712 if (rankDirBugEnabled == null)
713 rankDirBugEnabled = options.remove("-rankdirbug");
714
715 return rankDirBugEnabled;
716 }
717
718
719
720
721
722
723
724
725
726
727
728
729 public void setRailsEnabled(boolean enabled) {
730 railsEnabled = enabled;
731 }
732
733
734
735
736
737
738 public boolean isRailsEnabled() {
739 if (railsEnabled == null)
740 railsEnabled = options.remove("-rails");
741
742 return railsEnabled;
743 }
744
745
746
747
748 public void setEncodeCommentsEnabled(boolean enabled) {
749 encodeCommentsEnabled = enabled;
750 }
751
752
753
754
755 public boolean isEncodeCommentsEnabled() {
756 if (encodeCommentsEnabled == null)
757 encodeCommentsEnabled = !options.remove("-ahic");
758
759 return encodeCommentsEnabled;
760 }
761
762
763
764
765
766
767
768
769
770 public void setNumRowsEnabled(boolean enabled) {
771 numRowsEnabled = enabled;
772 }
773
774
775
776
777
778 public boolean isNumRowsEnabled() {
779 if (numRowsEnabled == null)
780 numRowsEnabled = !options.remove("-norows");
781
782 return numRowsEnabled;
783 }
784
785
786
787
788
789
790
791
792 public void setViewsEnabled(boolean enabled) {
793 viewsEnabled = enabled;
794 }
795
796
797
798
799
800 public boolean isViewsEnabled() {
801 if (viewsEnabled == null)
802 viewsEnabled = !options.remove("-noviews");
803
804 return viewsEnabled;
805 }
806
807
808
809
810
811
812
813 public boolean isMeterEnabled() {
814 if (meterEnabled == null)
815 meterEnabled = options.remove("-meter");
816
817 return meterEnabled;
818 }
819
820
821
822
823
824
825
826 public void setColumnExclusions(String columnExclusions) {
827 this.columnExclusions = Pattern.compile(columnExclusions);
828 }
829
830
831
832
833
834 public Pattern getColumnExclusions() {
835 if (columnExclusions == null) {
836 String strExclusions = pullParam("-X");
837 if (strExclusions == null)
838 strExclusions = "[^.]";
839
840 columnExclusions = Pattern.compile(strExclusions);
841 }
842
843 return columnExclusions;
844 }
845
846
847
848
849
850
851
852
853 public void setIndirectColumnExclusions(String fullColumnExclusions) {
854 indirectColumnExclusions = Pattern.compile(fullColumnExclusions);
855 }
856
857
858
859
860
861
862 public Pattern getIndirectColumnExclusions() {
863 if (indirectColumnExclusions == null) {
864 String strExclusions = pullParam("-x");
865 if (strExclusions == null)
866 strExclusions = "[^.]";
867
868 indirectColumnExclusions = Pattern.compile(strExclusions);
869 }
870
871 return indirectColumnExclusions;
872 }
873
874
875
876
877
878 public void setTableInclusions(String tableInclusions) {
879 this.tableInclusions = Pattern.compile(tableInclusions);
880 }
881
882
883
884
885
886
887 public Pattern getTableInclusions() {
888 if (tableInclusions == null) {
889 String strInclusions = pullParam("-i");
890 if (strInclusions == null)
891 strInclusions = ".*";
892
893 try {
894 tableInclusions = Pattern.compile(strInclusions);
895 } catch (PatternSyntaxException badPattern) {
896 throw new InvalidConfigurationException(badPattern).setParamName("-i");
897 }
898 }
899
900 return tableInclusions;
901 }
902
903
904
905
906
907 public void setTableExclusions(String tableExclusions) {
908 this.tableExclusions = Pattern.compile(tableExclusions);
909 }
910
911
912
913
914
915
916 public Pattern getTableExclusions() {
917 if (tableExclusions == null) {
918 String strExclusions = pullParam("-I");
919 if (strExclusions == null)
920 strExclusions = "";
921
922 try {
923 tableExclusions = Pattern.compile(strExclusions);
924 } catch (PatternSyntaxException badPattern) {
925 throw new InvalidConfigurationException(badPattern).setParamName("-I");
926 }
927 }
928
929 return tableExclusions;
930 }
931
932
933
934
935 public List<String> getSchemas() {
936 if (schemas == null) {
937 String tmp = pullParam("-schemas");
938 if (tmp == null)
939 tmp = pullParam("-schemata");
940 if (tmp != null) {
941 schemas = new ArrayList<String>();
942
943 for (String name : tmp.split("[ ,\"]"))
944 schemas.add(name);
945
946 if (schemas.isEmpty())
947 schemas = null;
948 }
949 }
950
951 return schemas;
952 }
953
954
955
956
957
958
959
960
961 public void setSqlFormatter(String formatterClassName) {
962 sqlFormatterClass = formatterClassName;
963 sqlFormatter = null;
964 }
965
966
967
968
969
970 public void setSqlFormatter(SqlFormatter sqlFormatter) {
971 this.sqlFormatter = sqlFormatter;
972 if (sqlFormatter != null)
973 sqlFormatterClass = sqlFormatter.getClass().getName();
974 }
975
976
977
978
979
980
981
982
983 @SuppressWarnings("unchecked")
984 public SqlFormatter getSqlFormatter() throws InvalidConfigurationException {
985 if (sqlFormatter == null) {
986 if (sqlFormatterClass == null) {
987 sqlFormatterClass = pullParam("-sqlFormatter");
988
989 if (sqlFormatterClass == null)
990 sqlFormatterClass = DefaultSqlFormatter.class.getName();
991 }
992
993 try {
994 Class<SqlFormatter> clazz = (Class<SqlFormatter>)Class.forName(sqlFormatterClass);
995 sqlFormatter = clazz.newInstance();
996 } catch (Exception exc) {
997 throw new InvalidConfigurationException("Failed to initialize instance of SQL formatter: ", exc)
998 .setParamName("-sqlFormatter");
999 }
1000 }
1001
1002 return sqlFormatter;
1003 }
1004
1005 public void setEvaluateAllEnabled(boolean enabled) {
1006 evaluteAll = enabled;
1007 }
1008
1009 public boolean isEvaluateAllEnabled() {
1010 if (evaluteAll == null)
1011 evaluteAll = options.remove("-all");
1012 return evaluteAll;
1013 }
1014
1015
1016
1017
1018
1019
1020
1021 public boolean isOneOfMultipleSchemas() {
1022
1023 return Boolean.getBoolean("oneofmultipleschemas");
1024 }
1025
1026
1027
1028
1029
1030
1031
1032 public void setSchemaSpec(String schemaSpec) {
1033 this.schemaSpec = schemaSpec;
1034 }
1035
1036 public String getSchemaSpec() {
1037 if (schemaSpec == null)
1038 schemaSpec = pullParam("-schemaSpec");
1039
1040 return schemaSpec;
1041 }
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 public void setRenderer(String renderer) {
1053 Dot.getInstance().setRenderer(renderer);
1054 }
1055
1056
1057
1058
1059
1060 public String getRenderer() {
1061 String renderer = pullParam("-renderer");
1062 if (renderer != null)
1063 setRenderer(renderer);
1064
1065 return Dot.getInstance().getRenderer();
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 public void setHighQuality(boolean highQuality) {
1080 this.highQuality = highQuality;
1081 lowQuality = !highQuality;
1082 Dot.getInstance().setHighQuality(highQuality);
1083 }
1084
1085
1086
1087
1088 public boolean isHighQuality() {
1089 if (highQuality == null) {
1090 highQuality = options.remove("-hq");
1091 if (highQuality) {
1092
1093 Dot.getInstance().setHighQuality(highQuality);
1094 }
1095 }
1096
1097 highQuality = Dot.getInstance().isHighQuality();
1098 return highQuality;
1099 }
1100
1101
1102
1103
1104 public boolean isLowQuality() {
1105 if (lowQuality == null) {
1106 lowQuality = options.remove("-lq");
1107 if (lowQuality) {
1108
1109 Dot.getInstance().setHighQuality(!lowQuality);
1110 }
1111 }
1112
1113 lowQuality = !Dot.getInstance().isHighQuality();
1114 return lowQuality;
1115 }
1116
1117
1118
1119
1120
1121
1122
1123
1124 public void setAdsEnabled(boolean enabled) {
1125 adsEnabled = enabled;
1126 }
1127
1128
1129
1130
1131
1132
1133
1134 @Deprecated
1135 public boolean isAdsEnabled() {
1136 if (adsEnabled == null) {
1137 adsEnabled = !options.remove("-noads");
1138 }
1139
1140 return adsEnabled ;
1141 }
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158 public void setLogLevel(String logLevel) {
1159 if (logLevel == null) {
1160 this.logLevel = Level.WARNING;
1161 return;
1162 }
1163
1164 Map<String, Level> levels = new LinkedHashMap<String, Level>();
1165 levels.put("severe", Level.SEVERE);
1166 levels.put("warning", Level.WARNING);
1167 levels.put("info", Level.INFO);
1168 levels.put("config", Level.CONFIG);
1169 levels.put("fine", Level.FINE);
1170 levels.put("finer", Level.FINER);
1171 levels.put("finest", Level.FINEST);
1172
1173 this.logLevel = levels.get(logLevel.toLowerCase());
1174 if (this.logLevel == null) {
1175 throw new InvalidConfigurationException("Invalid logLevel: '" + logLevel +
1176 "'. Must be one of: " + levels.keySet());
1177 }
1178 }
1179
1180
1181
1182
1183
1184
1185
1186 public Level getLogLevel() {
1187 if (logLevel == null) {
1188 setLogLevel(pullParam("-loglevel"));
1189 }
1190
1191 return logLevel;
1192 }
1193
1194
1195
1196
1197
1198
1199
1200 public boolean isHelpRequired() {
1201 return helpRequired;
1202 }
1203
1204 public boolean isDbHelpRequired() {
1205 return dbHelpRequired;
1206 }
1207
1208 public static String getLoadedFromJar() {
1209 String classpath = System.getProperty("java.class.path");
1210
1211 String originalPath = new StringTokenizer(classpath, File.pathSeparator).nextToken();
1212 String loadedFrom = null;
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222 URL location = Config.class.getProtectionDomain().getCodeSource().getLocation();
1223 File urlFile = null;
1224 try
1225 {
1226 try
1227 {
1228 urlFile= new File(location.toURI());
1229 }
1230 catch (URISyntaxException use)
1231 {
1232 urlFile= new File(location.getPath());
1233 }
1234 loadedFrom=urlFile.getCanonicalPath();
1235 }
1236 catch (IOException ioe)
1237 {
1238
1239 loadedFrom=originalPath;
1240 }
1241 return loadedFrom ;
1242 }
1243
1244
1245
1246
1247
1248
1249
1250 public Properties getDbProperties(String type) throws IOException, InvalidConfigurationException {
1251 ResourceBundle bundle = null;
1252
1253 try {
1254 File propertiesFile = new File(type);
1255 bundle = new PropertyResourceBundle(new FileInputStream(propertiesFile));
1256 dbPropertiesLoadedFrom = propertiesFile.getAbsolutePath();
1257 } catch (FileNotFoundException notFoundOnFilesystemWithoutExtension) {
1258 try {
1259 File propertiesFile = new File(type + ".properties");
1260 bundle = new PropertyResourceBundle(new FileInputStream(propertiesFile));
1261 dbPropertiesLoadedFrom = propertiesFile.getAbsolutePath();
1262 } catch (FileNotFoundException notFoundOnFilesystemWithExtensionTackedOn) {
1263 try {
1264 bundle = ResourceBundle.getBundle(type);
1265 dbPropertiesLoadedFrom = "[" + getLoadedFromJar() + "]" + File.separator + type + ".properties";
1266 } catch (Exception notInJarWithoutPath) {
1267 try {
1268 String path = TableOrderer.class.getPackage().getName() + ".dbTypes." + type;
1269 path = path.replace('.', '/');
1270 bundle = ResourceBundle.getBundle(path);
1271 dbPropertiesLoadedFrom = "[" + getLoadedFromJar() + "]/" + path + ".properties";
1272 } catch (Exception notInJar) {
1273 notInJar.printStackTrace();
1274 notFoundOnFilesystemWithExtensionTackedOn.printStackTrace();
1275 throw notFoundOnFilesystemWithoutExtension;
1276 }
1277 }
1278 }
1279 }
1280
1281 Properties props = asProperties(bundle);
1282 bundle = null;
1283 String saveLoadedFrom = dbPropertiesLoadedFrom;
1284
1285
1286
1287 for (int i = 1; true; ++i) {
1288 String include = (String)props.remove("include." + i);
1289 if (include == null)
1290 break;
1291
1292 int separator = include.indexOf("::");
1293 if (separator == -1)
1294 throw new InvalidConfigurationException("include directive in " + dbPropertiesLoadedFrom + " must have '::' between dbType and key");
1295
1296 String refdType = include.substring(0, separator).trim();
1297 String refdKey = include.substring(separator + 2).trim();
1298
1299
1300 Properties refdProps = getDbProperties(refdType);
1301 props.put(refdKey, refdProps.getProperty(refdKey));
1302 }
1303
1304
1305 String baseDbType = (String)props.remove("extends");
1306 if (baseDbType != null) {
1307 baseDbType = baseDbType.trim();
1308 Properties baseProps = getDbProperties(baseDbType);
1309
1310
1311 baseProps.putAll(props);
1312 props = baseProps;
1313 }
1314
1315
1316 dbPropertiesLoadedFrom = saveLoadedFrom;
1317
1318 return props;
1319 }
1320
1321 protected String getDbPropertiesLoadedFrom() throws IOException {
1322 if (dbPropertiesLoadedFrom == null)
1323 getDbProperties(getDbType());
1324 return dbPropertiesLoadedFrom;
1325 }
1326
1327 public List<String> getRemainingParameters()
1328 {
1329 try {
1330 populate();
1331 } catch (IllegalArgumentException exc) {
1332 throw new InvalidConfigurationException(exc);
1333 } catch (IllegalAccessException exc) {
1334 throw new InvalidConfigurationException(exc);
1335 } catch (InvocationTargetException exc) {
1336 if (exc.getCause() instanceof InvalidConfigurationException)
1337 throw (InvalidConfigurationException)exc.getCause();
1338 throw new InvalidConfigurationException(exc.getCause());
1339 } catch (IntrospectionException exc) {
1340 throw new InvalidConfigurationException(exc);
1341 }
1342
1343 return options;
1344 }
1345
1346
1347
1348
1349
1350
1351
1352 public void setDbSpecificOptions(Map<String, String> dbSpecificOptions) {
1353 this.dbSpecificOptions = dbSpecificOptions;
1354 originalDbSpecificOptions = new HashMap<String, String>(dbSpecificOptions);
1355 }
1356
1357 public Map<String, String> getDbSpecificOptions() {
1358 if (dbSpecificOptions == null)
1359 dbSpecificOptions = new HashMap<String, String>();
1360 return dbSpecificOptions;
1361 }
1362
1363
1364
1365
1366
1367
1368
1369 public static Properties asProperties(ResourceBundle bundle) {
1370 Properties props = new Properties();
1371 Enumeration<String> iter = bundle.getKeys();
1372 while (iter.hasMoreElements()) {
1373 String key = iter.nextElement();
1374 props.put(key, bundle.getObject(key));
1375 }
1376
1377 return props;
1378 }
1379
1380
1381
1382
1383
1384
1385
1386
1387 private String pullParam(String paramId) {
1388 return pullParam(paramId, false, false);
1389 }
1390
1391 private String pullRequiredParam(String paramId) {
1392 return pullParam(paramId, true, false);
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402 private String pullParam(String paramId, boolean required, boolean dbTypeSpecific)
1403 throws MissingRequiredParameterException {
1404 int paramIndex = options.indexOf(paramId);
1405 if (paramIndex < 0) {
1406 if (required)
1407 throw new MissingRequiredParameterException(paramId, dbTypeSpecific);
1408 return null;
1409 }
1410 options.remove(paramIndex);
1411 String param = options.get(paramIndex).toString();
1412 options.remove(paramIndex);
1413 return param;
1414 }
1415
1416
1417
1418
1419 public static class MissingRequiredParameterException extends RuntimeException {
1420 private static final long serialVersionUID = 1L;
1421 private final boolean dbTypeSpecific;
1422
1423 public MissingRequiredParameterException(String paramId, boolean dbTypeSpecific) {
1424 this(paramId, null, dbTypeSpecific);
1425 }
1426
1427 public MissingRequiredParameterException(String paramId, String description, boolean dbTypeSpecific) {
1428 super("Required parameter '" + paramId + "' " +
1429 (description == null ? "" : "(" + description + ") ") +
1430 "was not specified." +
1431 (dbTypeSpecific ? " It is required for this database type." : ""));
1432 this.dbTypeSpecific = dbTypeSpecific;
1433 }
1434
1435 public boolean isDbTypeSpecific() {
1436 return dbTypeSpecific;
1437 }
1438 }
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448 protected List<String> fixupArgs(List<String> args) {
1449 List<String> expandedArgs = new ArrayList<String>();
1450
1451 for (String arg : args) {
1452 int indexOfEquals = arg.indexOf('=');
1453 if (indexOfEquals != -1 && indexOfEquals -1 != arg.indexOf(ESCAPED_EQUALS)) {
1454 expandedArgs.add(arg.substring(0, indexOfEquals));
1455 expandedArgs.add(arg.substring(indexOfEquals + 1));
1456 } else {
1457 expandedArgs.add(arg);
1458 }
1459 }
1460
1461
1462
1463
1464 List<String> unquotedArgs = new ArrayList<String>();
1465
1466 for (String arg : expandedArgs) {
1467 if (arg.startsWith("\"") && arg.endsWith("\""))
1468 arg = arg.substring(1, arg.length() - 1);
1469 unquotedArgs.add(arg);
1470 }
1471
1472 return unquotedArgs;
1473 }
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483 private void populate() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException {
1484 if (!populating) {
1485 populating = true;
1486
1487 BeanInfo beanInfo = Introspector.getBeanInfo(Config.class);
1488 PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
1489 for (int i = 0; i < props.length; ++i) {
1490 Method readMethod = props[i].getReadMethod();
1491 if (readMethod != null)
1492 readMethod.invoke(this, (Object[])null);
1493 }
1494
1495 populating = false;
1496 }
1497 }
1498
1499 public static Set<String> getBuiltInDatabaseTypes(String loadedFromJar) {
1500 Set<String> databaseTypes = new TreeSet<String>();
1501 JarInputStream jar = null;
1502
1503 try {
1504 jar = new JarInputStream(new FileInputStream(loadedFromJar));
1505 JarEntry entry;
1506
1507 while ((entry = jar.getNextJarEntry()) != null) {
1508 String entryName = entry.getName();
1509 int dotPropsIndex = entryName.indexOf(".properties");
1510 if (dotPropsIndex != -1)
1511 databaseTypes.add(entryName.substring(0, dotPropsIndex));
1512 }
1513 } catch (IOException exc) {
1514 } finally {
1515 if (jar != null) {
1516 try {
1517 jar.close();
1518 } catch (IOException ignore) {}
1519 }
1520 }
1521
1522 return databaseTypes;
1523 }
1524
1525 protected void dumpUsage(String errorMessage, boolean detailedDb) {
1526 if (errorMessage != null) {
1527 System.out.flush();
1528 System.err.println("*** " + errorMessage + " ***");
1529 } else {
1530 System.out.println("SchemaSpy generates an HTML representation of a database schema's relationships.");
1531 }
1532
1533 System.err.flush();
1534 System.out.println();
1535
1536 if (!detailedDb) {
1537 System.out.println("Usage:");
1538 System.out.println(" java -jar " + getLoadedFromJar() + " [options]");
1539 System.out.println(" -t databaseType type of database - defaults to ora");
1540 System.out.println(" use -dbhelp for a list of built-in types");
1541 System.out.println(" -u user connect to the database with this user id");
1542 System.out.println(" -s schema defaults to the specified user");
1543 System.out.println(" -p password defaults to no password");
1544 System.out.println(" -o outputDirectory directory to place the generated output in");
1545 System.out.println(" -dp pathToDrivers optional - looks for JDBC drivers here before looking");
1546 System.out.println(" in driverPath in [databaseType].properties.");
1547 System.out.println("Go to http://schemaspy.sourceforge.net for a complete list/description");
1548 System.out.println(" of additional parameters.");
1549 System.out.println();
1550 }
1551
1552 if (detailedDb) {
1553 System.out.println("Built-in database types and their required connection parameters:");
1554 for (String type : getBuiltInDatabaseTypes(getLoadedFromJar())) {
1555 new DbSpecificConfig(type).dumpUsage();
1556 }
1557 System.out.println();
1558 }
1559
1560 if (detailedDb) {
1561 System.out.println("You can use your own database types by specifying the filespec of a .properties file with -t.");
1562 System.out.println("Grab one out of " + getLoadedFromJar() + " and modify it to suit your needs.");
1563 System.out.println();
1564 }
1565
1566 System.out.println("Sample usage using the default database type (implied -t ora):");
1567 System.out.println(" java -jar schemaSpy.jar -db mydb -s myschema -u devuser -p password -o output");
1568 System.out.println();
1569 System.out.flush();
1570 }
1571
1572
1573
1574
1575
1576
1577
1578
1579 public String getParam(String paramName) {
1580 try {
1581 BeanInfo beanInfo = Introspector.getBeanInfo(Config.class);
1582 PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
1583 for (int i = 0; i < props.length; ++i) {
1584 PropertyDescriptor prop = props[i];
1585 if (prop.getName().equalsIgnoreCase(paramName)) {
1586 Object result = prop.getReadMethod().invoke(this, (Object[])null);
1587 return result == null ? null : result.toString();
1588 }
1589 }
1590 } catch (Exception failed) {
1591 failed.printStackTrace();
1592 }
1593
1594 return null;
1595 }
1596
1597
1598
1599
1600
1601
1602
1603
1604 public List<String> asList() throws IOException {
1605 List<String> params = new ArrayList<String>();
1606
1607 if (originalDbSpecificOptions != null) {
1608 for (String key : originalDbSpecificOptions.keySet()) {
1609 String value = originalDbSpecificOptions.get(key);
1610 if (!key.startsWith("-"))
1611 key = "-" + key;
1612 params.add(key);
1613 params.add(value);
1614 }
1615 }
1616 if (isEncodeCommentsEnabled())
1617 params.add("-ahic");
1618 if (isEvaluateAllEnabled())
1619 params.add("-all");
1620 if (!isHtmlGenerationEnabled())
1621 params.add("-nohtml");
1622 if (!isImpliedConstraintsEnabled())
1623 params.add("-noimplied");
1624 if (!isLogoEnabled())
1625 params.add("-nologo");
1626 if (isMeterEnabled())
1627 params.add("-meter");
1628 if (!isNumRowsEnabled())
1629 params.add("-norows");
1630 if (!isViewsEnabled())
1631 params.add("-noviews");
1632 if (isRankDirBugEnabled())
1633 params.add("-rankdirbug");
1634 if (isRailsEnabled())
1635 params.add("-rails");
1636 if (isSingleSignOn())
1637 params.add("-sso");
1638 if (!isAdsEnabled())
1639 params.add("-noads");
1640 if (isSchemaDisabled())
1641 params.add("-noschema");
1642
1643 String value = getDriverPath();
1644 if (value != null) {
1645 params.add("-dp");
1646 params.add(value);
1647 }
1648 params.add("-css");
1649 params.add(getCss());
1650 params.add("-charset");
1651 params.add(getCharset());
1652 params.add("-font");
1653 params.add(getFont());
1654 params.add("-fontsize");
1655 params.add(String.valueOf(getFontSize()));
1656 params.add("-t");
1657 params.add(getDbType());
1658 params.add("-renderer");
1659 params.add(getRenderer());
1660 value = getDescription();
1661 if (value != null) {
1662 params.add("-desc");
1663 params.add(value);
1664 }
1665 value = getPassword();
1666 if (value != null) {
1667 params.add("-p");
1668 params.add(value);
1669 }
1670 if (isPromptForPasswordEnabled())
1671 params.add("-pfp");
1672 value = getSchema();
1673 if (value != null) {
1674 params.add("-s");
1675 params.add(value);
1676 }
1677 value = getUser();
1678 if (value != null) {
1679 params.add("-u");
1680 params.add(value);
1681 }
1682 value = getConnectionPropertiesFile();
1683 if (value != null) {
1684 params.add("-connprops");
1685 params.add(value);
1686 } else {
1687 Properties props = getConnectionProperties();
1688 if (!props.isEmpty() ) {
1689 params.add("-connprops");
1690 StringBuilder buf = new StringBuilder();
1691 for (Entry<Object, Object> entry : props.entrySet()) {
1692 buf.append(entry.getKey());
1693 buf.append(ESCAPED_EQUALS);
1694 buf.append(entry.getValue());
1695 buf.append(';');
1696 }
1697 params.add(buf.toString());
1698 }
1699 }
1700 value = getDb();
1701 if (value != null) {
1702 params.add("-db");
1703 params.add(value);
1704 }
1705 value = getHost();
1706 if (value != null) {
1707 params.add("-host");
1708 params.add(value);
1709 }
1710 if (getPort() != null) {
1711 params.add("-port");
1712 params.add(getPort().toString());
1713 }
1714 value = getServer();
1715 if (value != null) {
1716 params.add("-server");
1717 params.add(value);
1718 }
1719 value = getMeta();
1720 if (value != null) {
1721 params.add("-meta");
1722 params.add(value);
1723 }
1724 if (getGraphvizDir() != null) {
1725 params.add("-gv");
1726 params.add(getGraphvizDir().toString());
1727 }
1728 params.add("-loglevel");
1729 params.add(getLogLevel().toString().toLowerCase());
1730 params.add("-sqlFormatter");
1731 params.add(getSqlFormatter().getClass().getName());
1732 params.add("-i");
1733 params.add(getTableInclusions().pattern());
1734 params.add("-I");
1735 params.add(getTableExclusions().pattern());
1736 params.add("-x");
1737 params.add(getColumnExclusions().pattern());
1738 params.add("-X");
1739 params.add(getIndirectColumnExclusions().pattern());
1740 params.add("-dbthreads");
1741 params.add(String.valueOf(getMaxDbThreads()));
1742 params.add("-maxdet");
1743 params.add(String.valueOf(getMaxDetailedTables()));
1744 params.add("-o");
1745 params.add(getOutputDir().toString());
1746
1747 return params;
1748 }
1749 }