1 package org.apache.torque.engine.database.transform;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedInputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.util.Stack;
27 import java.util.Vector;
28
29 import javax.xml.parsers.SAXParser;
30 import javax.xml.parsers.SAXParserFactory;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.torque.engine.EngineException;
35 import org.apache.torque.engine.database.model.Column;
36 import org.apache.torque.engine.database.model.Database;
37 import org.apache.torque.engine.database.model.Domain;
38 import org.apache.torque.engine.database.model.ForeignKey;
39 import org.apache.torque.engine.database.model.Index;
40 import org.apache.torque.engine.database.model.Table;
41 import org.apache.torque.engine.database.model.Unique;
42 import org.kuali.core.db.torque.DatabaseParser;
43 import org.xml.sax.Attributes;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.SAXParseException;
47 import org.xml.sax.helpers.DefaultHandler;
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class XmlToAppData extends DefaultHandler implements DatabaseParser
62 {
63
64 private static Log log = LogFactory.getLog(XmlToAppData.class);
65
66 private Database database;
67 private Table currTable;
68 private Column currColumn;
69 private ForeignKey currFK;
70 private Index currIndex;
71 private Unique currUnique;
72
73 private boolean firstPass;
74 private boolean isExternalSchema;
75 private String currentPackage;
76 private String currentXmlFile;
77 private String defaultPackage;
78
79 private static SAXParserFactory saxFactory;
80
81
82 private Vector alreadyReadFiles;
83
84
85 private Stack parsingStack = new Stack();
86
87 static
88 {
89 saxFactory = SAXParserFactory.newInstance();
90 saxFactory.setValidating(true);
91 }
92
93
94
95
96
97
98 public XmlToAppData(String databaseType)
99 {
100 database = new Database(databaseType);
101 firstPass = true;
102 }
103
104
105
106
107
108
109
110 public XmlToAppData(String databaseType, String defaultPackage)
111 {
112 database = new Database(databaseType);
113 this.defaultPackage = defaultPackage;
114 firstPass = true;
115 }
116
117
118
119
120
121
122
123
124 public Database parseResource(String xmlFile)
125 throws EngineException
126 {
127 try
128 {
129
130 if (!firstPass)
131 {
132 throw new Error("No more double pass");
133 }
134
135 if ((alreadyReadFiles != null)
136 && alreadyReadFiles.contains(xmlFile))
137 {
138 return database;
139 }
140 else if (alreadyReadFiles == null)
141 {
142 alreadyReadFiles = new Vector(3, 1);
143 }
144
145
146 alreadyReadFiles.add(xmlFile);
147
148 currentXmlFile = xmlFile;
149
150 SAXParser parser = saxFactory.newSAXParser();
151
152 FileInputStream fileInputStream = null;
153 try
154 {
155 fileInputStream = new FileInputStream(xmlFile);
156 }
157 catch (FileNotFoundException fnfe)
158 {
159 throw new FileNotFoundException
160 (new File(xmlFile).getAbsolutePath());
161 }
162 BufferedInputStream bufferedInputStream
163 = new BufferedInputStream(fileInputStream);
164 try
165 {
166 log.info("Parsing file: '"
167 + (new File(xmlFile)).getName() + "'");
168 InputSource is = new InputSource(bufferedInputStream);
169 is.setSystemId( new File( xmlFile ).getAbsolutePath() );
170 parser.parse(is, this);
171 }
172 finally
173 {
174 bufferedInputStream.close();
175 }
176 }
177 catch (SAXParseException e)
178 {
179 throw new EngineException("Sax error on line "
180 + e.getLineNumber()
181 + " column "
182 + e.getColumnNumber()
183 + " : "
184 + e.getMessage(),
185 e);
186 }
187 catch (Exception e)
188 {
189 throw new EngineException(e);
190 }
191 if (!isExternalSchema)
192 {
193 firstPass = false;
194 }
195 database.doFinalInitialization();
196 return database;
197 }
198
199
200
201
202
203
204
205
206
207 public InputSource resolveEntity(String publicId, String systemId)
208 throws SAXException
209 {
210 try
211 {
212 return new DTDResolver().resolveEntity(publicId, systemId);
213 }
214 catch (Exception e)
215 {
216 throw new SAXException(e);
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230 public void startElement(String uri, String localName, String rawName,
231 Attributes attributes)
232 throws SAXException
233 {
234 try
235 {
236 if (rawName.equals("database"))
237 {
238 if (isExternalSchema)
239 {
240 currentPackage = attributes.getValue("package");
241 if (currentPackage == null)
242 {
243 currentPackage = defaultPackage;
244 }
245 }
246 else
247 {
248 database.loadFromXML(attributes);
249 if (database.getPackage() == null)
250 {
251 database.setPackage(defaultPackage);
252 }
253 }
254 }
255 else if (rawName.equals("external-schema"))
256 {
257 String xmlFile = attributes.getValue("filename");
258 if (xmlFile.charAt(0) != '/')
259 {
260 File f = new File(currentXmlFile);
261 xmlFile = new File(f.getParent(), xmlFile).getPath();
262 }
263
264
265 ParseStackElement.pushState(this);
266
267 isExternalSchema = true;
268
269 parseResource(xmlFile);
270
271 ParseStackElement.popState(this);
272 }
273 else if (rawName.equals("domain"))
274 {
275 Domain domain = new Domain();
276 domain.loadFromXML(attributes, database.getPlatform());
277 database.addDomain(domain);
278 }
279 else if (rawName.equals("table"))
280 {
281 currTable = database.addTable(attributes);
282 if (isExternalSchema)
283 {
284 currTable.setForReferenceOnly(true);
285 currTable.setPackage(currentPackage);
286 }
287 }
288 else if (rawName.equals("column"))
289 {
290 currColumn = currTable.addColumn(attributes);
291 }
292 else if (rawName.equals("inheritance"))
293 {
294 currColumn.addInheritance(attributes);
295 }
296 else if (rawName.equals("foreign-key"))
297 {
298 currFK = currTable.addForeignKey(attributes);
299 }
300 else if (rawName.equals("reference"))
301 {
302 currFK.addReference(attributes);
303 }
304 else if (rawName.equals("index"))
305 {
306 currIndex = currTable.addIndex(attributes);
307 }
308 else if (rawName.equals("index-column"))
309 {
310 currIndex.addColumn(attributes);
311 }
312 else if (rawName.equals("unique"))
313 {
314 currUnique = currTable.addUnique(attributes);
315 }
316 else if (rawName.equals("unique-column"))
317 {
318 currUnique.addColumn(attributes);
319 }
320 else if (rawName.equals("id-method-parameter"))
321 {
322 currTable.addIdMethodParameter(attributes);
323 }
324 else if (rawName.equals("option"))
325 {
326 setOption(attributes);
327 }
328 }
329 catch (Exception e)
330 {
331 throw new SAXException(e);
332 }
333 }
334
335
336
337
338
339
340
341
342
343
344 public void endElement(String uri, String localName, String rawName)
345 throws SAXException
346 {
347 if (log.isDebugEnabled())
348 {
349 log.debug("endElement(" + uri + ", " + localName + ", "
350 + rawName + ") called");
351 }
352 try
353 {
354
355
356 if (rawName.equals("table"))
357 {
358 currTable = null;
359 }
360 else if (rawName.equals("column"))
361 {
362 currColumn = null;
363 }
364 else if (rawName.equals("foreign-key"))
365 {
366 currFK = null;
367 }
368 else if (rawName.equals("index"))
369 {
370 currIndex = null;
371 }
372 else if (rawName.equals("unique"))
373 {
374 currUnique = null;
375 }
376 }
377 catch (Exception e)
378 {
379 throw new SAXException(e);
380 }
381 }
382
383 public void setOption(Attributes attributes)
384 {
385
386
387
388 String key = attributes.getValue("key");
389 String value = attributes.getValue("value");
390 if (currUnique != null)
391 {
392 currUnique.addOption(key, value);
393 }
394 else if (currIndex != null)
395 {
396 currIndex.addOption(key, value);
397 }
398 else if (currFK != null)
399 {
400 currFK.addOption(key, value);
401 }
402 else if (currColumn != null)
403 {
404 currColumn.addOption(key, value);
405 }
406 else if (currTable != null)
407 {
408 currTable.addOption(key, value);
409 }
410 else
411 {
412 database.addOption(key, value);
413 }
414 }
415
416
417
418
419
420
421 public void error(SAXParseException e) throws SAXException
422 {
423 log.error("Sax parser threw an Exception", e);
424 throw new SAXException(
425 "Error while parsing "
426 + currentXmlFile
427 + " at line "
428 + e.getLineNumber()
429 + " column "
430 + e.getColumnNumber()
431 + " : "
432 + e.getMessage());
433 }
434
435
436
437
438
439 private static class ParseStackElement
440 {
441 private boolean isExternalSchema;
442 private String currentPackage;
443 private String currentXmlFile;
444 private boolean firstPass;
445
446
447
448
449
450 public ParseStackElement(XmlToAppData parser)
451 {
452
453 isExternalSchema = parser.isExternalSchema;
454 currentPackage = parser.currentPackage;
455 currentXmlFile = parser.currentXmlFile;
456 firstPass = parser.firstPass;
457
458
459 parser.parsingStack.push(this);
460 }
461
462
463
464
465
466
467 public static void popState(XmlToAppData parser)
468 {
469 if (!parser.parsingStack.isEmpty())
470 {
471 ParseStackElement elem = (ParseStackElement)
472 parser.parsingStack.pop();
473
474
475 parser.isExternalSchema = elem.isExternalSchema;
476 parser.currentPackage = elem.currentPackage;
477 parser.currentXmlFile = elem.currentXmlFile;
478 parser.firstPass = elem.firstPass;
479 }
480 }
481
482
483
484
485
486
487 public static void pushState(XmlToAppData parser)
488 {
489 new ParseStackElement(parser);
490 }
491 }
492 }