1 package pl.aislib.tools.mapping;
2
3 import pl.aislib.tools.mapping.db.Database;
4
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.FileWriter;
8 import java.io.IOException;
9 import java.io.Writer;
10 import java.sql.SQLException;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Properties;
15 import java.util.Set;
16 import java.util.Vector;
17
18 import javax.xml.transform.OutputKeys;
19 import javax.xml.transform.Transformer;
20 import javax.xml.transform.TransformerFactory;
21 import javax.xml.transform.stream.StreamSource;
22
23 import org.jdom.DocType;
24 import org.jdom.Document;
25 import org.jdom.Element;
26 import org.jdom.EntityRef;
27 import org.jdom.output.XMLOutputter;
28 import org.jdom.transform.JDOMResult;
29 import org.jdom.transform.JDOMSource;
30
31 /***
32 * Generates structure.xml file from an existing database.
33 *
34 * @author Michal Jastak, AIS.PL
35 * @author Tomasz Pik, AIS.PL
36 * @author Milosz Tylenda, AIS.PL
37 * @version $Revision: 1.6 $
38 */
39 public class Describe {
40
41 private static final String DB_PARTS_DIR = "db_parts";
42
43 /***
44 * When true and short version requested, the 'default' attribute will not
45 * be set in java-field element.
46 */
47 private boolean noDefault;
48
49 private boolean separateFiles;
50 private boolean verboseFlag;
51 private boolean fixedTableTypes;
52 private Database dBase;
53 private Properties dBaseProperties;
54 private String configFilePath;
55 private String dbCatalog;
56 private String dbDriver;
57 private String dbPassword;
58 private String dbSchema;
59 private String dbURL;
60 private String dbUser;
61
62 private Set tables;
63
64 /***
65 *
66 */
67
68 public Describe() {
69 verboseFlag = false;
70 fixedTableTypes = false;
71 configFilePath = "describe.conf";
72 dBaseProperties = new Properties();
73 }
74
75 public boolean inSeparateFiles() {
76 return separateFiles;
77 }
78
79 /***
80 *
81 */
82
83 public boolean verbose() {
84 return verboseFlag;
85 }
86
87 /***
88 *
89 */
90
91 public void initialize() throws IOException, SQLException {
92 try {
93 dBaseProperties.load(new FileInputStream(configFilePath));
94 } catch (IOException ioe) {
95
96 }
97 if (dbCatalog == null) {
98 dbCatalog = dBaseProperties.getProperty("catalog");
99 }
100 if (dbDriver == null) {
101 dbDriver = dBaseProperties.getProperty("driver");
102 }
103 if (dbPassword == null) {
104 dbPassword = dBaseProperties.getProperty("password");
105 }
106 if (dbSchema == null) {
107 dbSchema = dBaseProperties.getProperty("schema");
108 }
109 if (dbURL == null) {
110 dbURL = dBaseProperties.getProperty("url");
111 }
112 if (dbUser == null) {
113 dbUser = dBaseProperties.getProperty("user");
114 }
115
116 if (verboseFlag) {
117 System.err.println(
118 "\nInitialized as follows:\n"
119 + "\n\tDriver: "
120 + dbDriver
121 + "\n\tURL: "
122 + dbURL
123 + "\n\tUser: "
124 + dbUser
125 + "\n\tPassword: "
126 + dbPassword
127 + "\n\tCatalog: "
128 + dbCatalog
129 + "\n\tSchema: "
130 + dbSchema);
131 }
132
133 dBase = new Database(verboseFlag);
134 dBase.setCatalog(dbCatalog);
135 dBase.setDriver(dbDriver);
136 dBase.setSchema(dbSchema);
137 dBase.connect(dbURL, dbUser, dbPassword);
138 }
139
140 /***
141 *
142 */
143 public void readTables() throws SQLException {
144 dBase.readTables(fixedTableTypes, tables);
145 }
146
147 /***
148 *
149 */
150 public void readSequences() throws SQLException {
151 dBase.readSequences();
152 }
153
154 /***
155 *
156 */
157 public void genericInfo() throws SQLException {
158 dBase.genericInfo();
159 }
160
161 /***
162 *
163 */
164 public String toString() {
165 return dBase.toString();
166 }
167
168 public void writeToSeparateFiles(boolean isShort) throws Exception {
169 List xmls = dBase.toSeparateXMLs();
170 for (Iterator iter = xmls.iterator(); iter.hasNext();) {
171 XmlDesc xmlDesc = (XmlDesc) iter.next();
172
173 String xmlName = xmlDesc.getName();
174 Element root = xmlDesc.getElement();
175
176 Vector cnt = new Vector();
177 cnt.add(root);
178 Document doc = new Document(cnt);
179
180 if (isShort) {
181 TransformerFactory tFactory = TransformerFactory.newInstance();
182
183 StreamSource style = getStyle();
184 JDOMResult result = new JDOMResult();
185 JDOMSource source = new JDOMSource(doc);
186
187 Transformer trans = tFactory.newTransformer(style);
188 trans.setOutputProperty(OutputKeys.METHOD, "xml");
189 trans.setOutputProperty(OutputKeys.INDENT, "yes");
190 trans.transform(source, result);
191 doc = result.getDocument();
192 }
193 XMLOutputter xo = new XMLOutputter(" ", true);
194 xo.setOmitDeclaration(true);
195
196 String xoDoc = xo.outputString(doc);
197
198 Writer writer = new FileWriter(DB_PARTS_DIR + File.separatorChar + xmlName + ".xml");
199 writer.write(xoDoc.toString());
200 writer.close();
201
202 System.out.println("Saved: " + xmlName + ".xml");
203 }
204
205 if (tables == null) {
206 System.out.println("Saved: structure.xml");
207
208 Element root = new Element("database");
209
210 for (Iterator iter = xmls.iterator(); iter.hasNext();) {
211 XmlDesc xmlDesc = (XmlDesc) iter.next();
212 String xmlName = xmlDesc.getName();
213 EntityRef entityRef = new EntityRef("db_part_" + xmlName);
214 root.addContent(entityRef);
215 }
216 Vector cnt = new Vector();
217 cnt.add(root);
218 Document doc = new Document(cnt);
219
220 DocType docType =
221 new DocType("database", "-//AIS.PL//DTD Mapping Description 0.4//EN", "http://www.ais.pl/dtds/mapping_0_4.dtd");
222
223 StringBuffer entities = new StringBuffer();
224 for (Iterator iter = xmls.iterator(); iter.hasNext();) {
225 XmlDesc xmlDesc = (XmlDesc) iter.next();
226 String xmlName = xmlDesc.getName();
227 entities.append(
228 "<!ENTITY db_part_" + xmlName + " SYSTEM \"./" + DB_PARTS_DIR + "/" + xmlName + ".xml\">\n");
229 }
230 docType.setInternalSubset(entities.toString());
231
232 doc.setDocType(docType);
233
234 XMLOutputter xo = new XMLOutputter(" ", true);
235 xo.setEncoding("iso-8859-2");
236 String xoDoc = xo.outputString(doc);
237 Writer writer = new FileWriter("structure.xml");
238 writer.write(xoDoc.toString());
239 writer.close();
240 }
241
242 }
243
244 /***
245 *
246 */
247 public void writeTo(boolean isShort) throws Exception {
248 Element root = dBase.toXML();
249 Vector cnt = new Vector();
250 cnt.add(root);
251 Document doc = new Document(cnt);
252
253 if (isShort) {
254 TransformerFactory tFactory = TransformerFactory.newInstance();
255
256 StreamSource style = getStyle();
257 JDOMResult result = new JDOMResult();
258 JDOMSource source = new JDOMSource(doc);
259
260 Transformer trans = tFactory.newTransformer(style);
261 trans.setOutputProperty(OutputKeys.METHOD, "xml");
262 trans.setOutputProperty(OutputKeys.INDENT, "yes");
263 trans.transform(source, result);
264 doc = result.getDocument();
265 doc.setDocType(
266 new DocType(
267 "database",
268 "-//AIS.PL//DTD Mapping Description 0.4//EN",
269 "http://www.ais.pl/dtds/mapping_0_4.dtd"));
270 }
271 XMLOutputter xo = new XMLOutputter(" ", true);
272 xo.setEncoding("iso-8859-2");
273 String xoDoc = xo.outputString(doc);
274 System.out.println(xoDoc);
275 }
276
277 /***
278 * Returns the suitable StreamSource depending on the noDefault value.
279 */
280 private StreamSource getStyle() {
281 if (noDefault) {
282 return new StreamSource(
283 Thread.currentThread().getContextClassLoader().getResourceAsStream("pl/aislib/tools/mapping/mapping-no-default.xsl"));
284 } else {
285 return new StreamSource(
286 Thread.currentThread().getContextClassLoader().getResourceAsStream("pl/aislib/tools/mapping/mapping.xsl"));
287 }
288 }
289
290 /***
291 *
292 */
293 public void parseArgs(String ArgV[]) throws ArrayIndexOutOfBoundsException {
294 int i = 0;
295 while (i < ArgV.length) {
296 if (ArgV[i].equals("--config-file") || ArgV[i].equals("-c")) {
297 i++;
298 configFilePath = ArgV[i];
299 }
300
301 if (ArgV[i].equals("--catalog") || ArgV[i].equals("-t")) {
302 i++;
303 dbCatalog = ArgV[i];
304 }
305
306 if (ArgV[i].equals("--driver") || ArgV[i].equals("-d")) {
307 i++;
308 dbDriver = ArgV[i];
309 }
310
311 if (ArgV[i].equals("--password") || ArgV[i].equals("-p")) {
312 i++;
313 dbPassword = ArgV[i];
314 }
315
316 if (ArgV[i].equals("--schema") || ArgV[i].equals("-s")) {
317 i++;
318 dbSchema = ArgV[i];
319 }
320
321 if (ArgV[i].equals("--url") || ArgV[i].equals("-r")) {
322 i++;
323 dbURL = ArgV[i];
324 }
325
326 if (ArgV[i].equals("--user") || ArgV[i].equals("-u")) {
327 i++;
328 dbUser = ArgV[i];
329 }
330
331 if (ArgV[i].equals("--verbose") || ArgV[i].equals("-v")) {
332 verboseFlag = true;
333 }
334
335 if (ArgV[i].equals("--files") || ArgV[i].equals("-f")) {
336 separateFiles = true;
337 }
338
339 if (ArgV[i].equals("--table") || ArgV[i].equals("-T")) {
340 i++;
341 if (tables == null) {
342 tables = new HashSet();
343 }
344 tables.add(ArgV[i]);
345 }
346
347 if (ArgV[i].equals("--fixed-table-types")) {
348 fixedTableTypes = true;
349 }
350
351 if (ArgV[i].equals("--no-default-values")) {
352 noDefault = true;
353 }
354
355 i++;
356 }
357 }
358
359 /***
360 *
361 */
362
363 public String usageDescription() {
364
365 StringBuffer result = new StringBuffer();
366 result.append("\nUsage:\n");
367 result.append("\t-c, --config-file config file path\n");
368 result.append("\nConfiguration options may be overwritten using following options:\n\n");
369 result.append("\t-d, --driver JDBC driver class name\n");
370 result.append("\t-p, --password password for database access authorization\n");
371 result.append("\t-r, --url database URL\n");
372 result.append("\t-s, --schema database schema\n");
373 result.append("\t-t, --catalog database catalog\n");
374 result.append("\t-u, --user user name for database access authorization\n");
375 result.append("\nOther options:\n\n");
376 result.append("\t--fixed-table-types use only TABLE and VIEW as possible table types\n");
377 result.append("\t--short short version (for tools-mapping)\n");
378 result.append("\t--no-default-values do not output 'default' attributes in <java-field>\n");
379 result.append("\t-v, --verbose turn on verbose mode\n");
380 result.append("\t-T, --table generate description for one table\n");
381 result.append("\t-f, --files create file for each table\n");
382 result.append("\nVersion: $Name: $\n");
383 return new String(result);
384 }
385
386 /***
387 *
388 */
389
390 public static void main(String ArgV[]) {
391
392 Describe describe = new Describe();
393 if (ArgV.length == 0) {
394 System.out.println(describe.usageDescription());
395 System.exit(1);
396 }
397 try {
398 describe.parseArgs(ArgV);
399 } catch (Exception ex) {
400 System.err.println(describe.usageDescription());
401 System.exit(1);
402 }
403
404 try {
405 describe.initialize();
406 } catch (Exception ex) {
407 System.err.println("\nException caught during initialization:\n\n\t" + ex.getMessage());
408 if (describe.verbose()) {
409 ex.printStackTrace();
410 }
411 System.exit(2);
412 }
413
414 try {
415 describe.genericInfo();
416 describe.readTables();
417 describe.readSequences();
418
419 boolean isShort = false;
420 for (int i = 0; i < ArgV.length; i++) {
421 if ((ArgV[i].equals("--short")) || (ArgV[i].equals("-s"))) {
422 isShort = true;
423 }
424 }
425 if (describe.inSeparateFiles()) {
426 describe.writeToSeparateFiles(isShort);
427 } else {
428 describe.writeTo(isShort);
429 }
430 } catch (Exception ex) {
431 System.err.println("\nException caught:\n\n\t" + ex.getMessage());
432 if (describe.verbose()) {
433 ex.printStackTrace();
434 }
435 System.exit(3);
436 }
437 }
438
439 }
440
441 /***
442 * $Log: Describe.java,v $
443 * Revision 1.6 2004/06/24 05:46:10 milosz
444 * Class comment added.
445 *
446 * Revision 1.5 2004/01/19 14:35:02 milosz
447 * Support for --no-default-values added.
448 *
449 */