KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > torque > engine > database > transform > XmlToAppData


1 package org.apache.torque.engine.database.transform;
2
3 /*
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.io.BufferedReader JavaDoc;
20 import java.io.File JavaDoc;
21 import java.io.FileNotFoundException JavaDoc;
22 import java.io.FileReader JavaDoc;
23 import java.util.Stack JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import javax.xml.parsers.SAXParser JavaDoc;
27 import javax.xml.parsers.SAXParserFactory JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.torque.engine.EngineException;
32 import org.apache.torque.engine.database.model.Column;
33 import org.apache.torque.engine.database.model.Database;
34 import org.apache.torque.engine.database.model.Domain;
35 import org.apache.torque.engine.database.model.ForeignKey;
36 import org.apache.torque.engine.database.model.Index;
37 import org.apache.torque.engine.database.model.Table;
38 import org.apache.torque.engine.database.model.Unique;
39 import org.xml.sax.Attributes JavaDoc;
40 import org.xml.sax.InputSource JavaDoc;
41 import org.xml.sax.SAXException JavaDoc;
42 import org.xml.sax.SAXParseException JavaDoc;
43 import org.xml.sax.helpers.DefaultHandler JavaDoc;
44
45 /**
46  * A Class that is used to parse an input xml schema file and creates a Database
47  * java structure.
48  *
49  * @author <a HREF="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
50  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
51  * @author <a HREF="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
52  * @author <a HREF="mailto:dlr@collab.net">Daniel Rall</a>
53  * @author <a HREF="mailto:fischer@seitenbau.de">Thomas Fischer</a>
54  * @version $Id: XmlToAppData.java,v 1.15 2005/06/26 06:49:59 tfischer Exp $
55  */

56 public class XmlToAppData extends DefaultHandler JavaDoc
57 {
58     /** Logging class from commons.logging */
59     private static Log log = LogFactory.getLog(XmlToAppData.class);
60
61     private Database database;
62     private Table currTable;
63     private Column currColumn;
64     private ForeignKey currFK;
65     private Index currIndex;
66     private Unique currUnique;
67
68     private boolean firstPass;
69     private boolean isExternalSchema;
70     private String JavaDoc currentPackage;
71     private String JavaDoc currentXmlFile;
72     private String JavaDoc defaultPackage;
73
74     private static SAXParserFactory JavaDoc saxFactory;
75
76     /** remember all files we have already parsed to detect looping. */
77     private Vector JavaDoc alreadyReadFiles;
78
79     /** this is the stack to store parsing data */
80     private Stack JavaDoc parsingStack = new Stack JavaDoc();
81
82     static
83     {
84         saxFactory = SAXParserFactory.newInstance();
85         saxFactory.setValidating(true);
86     }
87
88     /**
89      * Creates a new instance for the specified database type.
90      *
91      * @param databaseType The type of database for the application.
92      */

93     public XmlToAppData(String JavaDoc databaseType)
94     {
95         database = new Database(databaseType);
96         firstPass = true;
97     }
98
99     /**
100      * Creates a new instance for the specified database type.
101      *
102      * @param databaseType The type of database for the application.
103      * @param defaultPackage the default java package used for the om
104      */

105     public XmlToAppData(String JavaDoc databaseType, String JavaDoc defaultPackage)
106     {
107         database = new Database(databaseType);
108         this.defaultPackage = defaultPackage;
109         firstPass = true;
110     }
111
112     /**
113      * Parses a XML input file and returns a newly created and
114      * populated Database structure.
115      *
116      * @param xmlFile The input file to parse.
117      * @return Database populated by <code>xmlFile</code>.
118      */

119     public Database parseFile(String JavaDoc xmlFile)
120             throws EngineException
121     {
122         try
123         {
124             // in case I am missing something, make it obvious
125
if (!firstPass)
126             {
127                 throw new Error JavaDoc("No more double pass");
128             }
129             // check to see if we alread have parsed the file
130
if ((alreadyReadFiles != null)
131                     && alreadyReadFiles.contains(xmlFile))
132             {
133                 return database;
134             }
135             else if (alreadyReadFiles == null)
136             {
137                 alreadyReadFiles = new Vector JavaDoc(3, 1);
138             }
139             
140             // remember the file to avoid looping
141
alreadyReadFiles.add(xmlFile);
142             
143             currentXmlFile = xmlFile;
144             
145             SAXParser JavaDoc parser = saxFactory.newSAXParser();
146             
147             FileReader JavaDoc fr = null;
148             try
149             {
150                 fr = new FileReader JavaDoc(xmlFile);
151             }
152             catch (FileNotFoundException JavaDoc fnfe)
153             {
154                 throw new FileNotFoundException JavaDoc
155                     (new File JavaDoc(xmlFile).getAbsolutePath());
156             }
157             BufferedReader JavaDoc br = new BufferedReader JavaDoc(fr);
158             try
159             {
160                 log.info("Parsing file: '"
161                         + (new File JavaDoc(xmlFile)).getName() + "'");
162                 InputSource JavaDoc is = new InputSource JavaDoc(br);
163                 parser.parse(is, this);
164             }
165             finally
166             {
167                 br.close();
168             }
169         }
170         catch (Exception JavaDoc e)
171         {
172             throw new EngineException(e);
173         }
174         if (!isExternalSchema)
175         {
176             firstPass = false;
177         }
178         database.doFinalInitialization();
179         return database;
180     }
181     
182     /**
183      * EntityResolver implementation. Called by the XML parser
184      *
185      * @param publicId The public identifier of the external entity
186      * @param systemId The system identifier of the external entity
187      * @return an InputSource for the database.dtd file
188      * @see DTDResolver#resolveEntity(String, String)
189      */

190     public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
191             throws SAXException JavaDoc
192     {
193         try
194         {
195             return new DTDResolver().resolveEntity(publicId, systemId);
196         }
197         catch (Exception JavaDoc e)
198         {
199             throw new SAXException JavaDoc(e);
200         }
201     }
202
203     /**
204      * Handles opening elements of the xml file.
205      *
206      * @param uri
207      * @param localName The local name (without prefix), or the empty string if
208      * Namespace processing is not being performed.
209      * @param rawName The qualified name (with prefix), or the empty string if
210      * qualified names are not available.
211      * @param attributes The specified or defaulted attributes
212      */

213     public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc rawName,
214                              Attributes JavaDoc attributes)
215             throws SAXException JavaDoc
216     {
217         try
218         {
219             if (rawName.equals("database"))
220             {
221                 if (isExternalSchema)
222                 {
223                     currentPackage = attributes.getValue("package");
224                     if (currentPackage == null)
225                     {
226                         currentPackage = defaultPackage;
227                     }
228                 }
229                 else
230                 {
231                     database.loadFromXML(attributes);
232                     if (database.getPackage() == null)
233                     {
234                         database.setPackage(defaultPackage);
235                     }
236                 }
237             }
238             else if (rawName.equals("external-schema"))
239             {
240                 String JavaDoc xmlFile = attributes.getValue("filename");
241                 if (xmlFile.charAt(0) != '/')
242                 {
243                     File JavaDoc f = new File JavaDoc(currentXmlFile);
244                     xmlFile = new File JavaDoc(f.getParent(), xmlFile).getPath();
245                 }
246
247                 // put current state onto the stack
248
ParseStackElement.pushState(this);
249
250                 isExternalSchema = true;
251
252                 parseFile(xmlFile);
253                 // get the last state from the stack
254
ParseStackElement.popState(this);
255             }
256             else if (rawName.equals("domain"))
257             {
258                 Domain domain = new Domain();
259                 domain.loadFromXML(attributes, database.getPlatform());
260                 database.addDomain(domain);
261             }
262             else if (rawName.equals("table"))
263             {
264                 currTable = database.addTable(attributes);
265                 if (isExternalSchema)
266                 {
267                     currTable.setForReferenceOnly(true);
268                     currTable.setPackage(currentPackage);
269                 }
270             }
271             else if (rawName.equals("column"))
272             {
273                 currColumn = currTable.addColumn(attributes);
274             }
275             else if (rawName.equals("inheritance"))
276             {
277                 currColumn.addInheritance(attributes);
278             }
279             else if (rawName.equals("foreign-key"))
280             {
281                 currFK = currTable.addForeignKey(attributes);
282             }
283             else if (rawName.equals("reference"))
284             {
285                 currFK.addReference(attributes);
286             }
287             else if (rawName.equals("index"))
288             {
289                 currIndex = currTable.addIndex(attributes);
290             }
291             else if (rawName.equals("index-column"))
292             {
293                 currIndex.addColumn(attributes);
294             }
295             else if (rawName.equals("unique"))
296             {
297                 currUnique = currTable.addUnique(attributes);
298             }
299             else if (rawName.equals("unique-column"))
300             {
301                 currUnique.addColumn(attributes);
302             }
303             else if (rawName.equals("id-method-parameter"))
304             {
305                 currTable.addIdMethodParameter(attributes);
306             }
307         }
308         catch (Exception JavaDoc e)
309         {
310             throw new SAXException JavaDoc(e);
311         }
312     }
313
314     /**
315      * Handles closing elements of the xml file.
316      *
317      * @param uri
318      * @param localName The local name (without prefix), or the empty string if
319      * Namespace processing is not being performed.
320      * @param rawName The qualified name (with prefix), or the empty string if
321      * qualified names are not available.
322      */

323     public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc rawName)
324     {
325         if (log.isDebugEnabled())
326         {
327             log.debug("endElement(" + uri + ", " + localName + ", "
328                     + rawName + ") called");
329         }
330     }
331     
332     /**
333      * Handles exception which occur when the xml file is parsed
334      * @param e the exception which occured while parsing
335      * @throws SAXException always
336      */

337     public void error(SAXParseException JavaDoc e) throws SAXException JavaDoc
338     {
339         log.error("Sax parser threw an Exception", e);
340         throw new SAXException JavaDoc(
341                 "Error while parsing "
342                 + currentXmlFile
343                 + " at line "
344                 + e.getLineNumber()
345                 + " column "
346                 + e.getColumnNumber()
347                 + " : "
348                 + e.getMessage());
349     }
350
351     /**
352      * When parsing multiple files that use nested <external-schema> tags we
353      * need to use a stack to remember some values.
354      */

355     private static class ParseStackElement
356     {
357         private boolean isExternalSchema;
358         private String JavaDoc currentPackage;
359         private String JavaDoc currentXmlFile;
360         private boolean firstPass;
361
362         /**
363          *
364          * @param parser
365          */

366         public ParseStackElement(XmlToAppData parser)
367         {
368             // remember current state of parent object
369
isExternalSchema = parser.isExternalSchema;
370             currentPackage = parser.currentPackage;
371             currentXmlFile = parser.currentXmlFile;
372             firstPass = parser.firstPass;
373
374             // push the state onto the stack
375
parser.parsingStack.push(this);
376         }
377
378         /**
379          * Removes the top element from the stack and activates the stored state
380          *
381          * @param parser
382          */

383         public static void popState(XmlToAppData parser)
384         {
385             if (!parser.parsingStack.isEmpty())
386             {
387                 ParseStackElement elem = (ParseStackElement)
388                         parser.parsingStack.pop();
389
390                 // activate stored state
391
parser.isExternalSchema = elem.isExternalSchema;
392                 parser.currentPackage = elem.currentPackage;
393                 parser.currentXmlFile = elem.currentXmlFile;
394                 parser.firstPass = elem.firstPass;
395             }
396         }
397
398         /**
399          * Stores the current state on the top of the stack.
400          *
401          * @param parser
402          */

403         public static void pushState(XmlToAppData parser)
404         {
405             new ParseStackElement(parser);
406         }
407     }
408 }
409
Popular Tags