Clover Coverage Report - Impex Parent 1.0.21-SNAPSHOT (Aggregated)
Coverage timestamp: Tue Feb 8 2011 11:33:53 EST
../../../../../../img/srcFileCovDistChart0.png 0% of files have more coverage
126   492   54   10.5
70   346   0.43   6
12     4.5  
2    
 
  XmlToAppData       Line # 61 114 0% 50 191 0% 0.0
  XmlToAppData.ParseStackElement       Line # 439 12 0% 4 17 0% 0.0
 
No Tests
 
1    package org.apache.torque.engine.database.transform;
2   
3    /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements. See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership. The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10    * with the License. You may obtain a copy of the License at
11    *
12    * http://www.apache.org/licenses/LICENSE-2.0
13    *
14    * Unless required by applicable law or agreed to in writing,
15    * software distributed under the License is distributed on an
16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17    * KIND, either express or implied. See the License for the
18    * specific language governing permissions and limitations
19    * under the License.
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    * A Class that is used to parse an input xml schema file and creates a Database
51    * java structure.
52    *
53    * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
54    * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
55    * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
56    * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
57    * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
58    * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a>
59    * @version $Id: XmlToAppData.java,v 1.1 2007-10-21 07:57:26 abyrne Exp $
60    */
 
61    public class XmlToAppData extends DefaultHandler implements DatabaseParser
62    {
63    /** Logging class from commons.logging */
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    /** remember all files we have already parsed to detect looping. */
82    private Vector alreadyReadFiles;
83   
84    /** this is the stack to store parsing data */
85    private Stack parsingStack = new Stack();
86   
 
87  0 toggle static
88    {
89  0 saxFactory = SAXParserFactory.newInstance();
90  0 saxFactory.setValidating(true);
91    }
92   
93    /**
94    * Creates a new instance for the specified database type.
95    *
96    * @param databaseType The type of database for the application.
97    */
 
98  0 toggle public XmlToAppData(String databaseType)
99    {
100  0 database = new Database(databaseType);
101  0 firstPass = true;
102    }
103   
104    /**
105    * Creates a new instance for the specified database type.
106    *
107    * @param databaseType The type of database for the application.
108    * @param defaultPackage the default java package used for the om
109    */
 
110  0 toggle public XmlToAppData(String databaseType, String defaultPackage)
111    {
112  0 database = new Database(databaseType);
113  0 this.defaultPackage = defaultPackage;
114  0 firstPass = true;
115    }
116   
117    /**
118    * Parses a XML input file and returns a newly created and
119    * populated Database structure.
120    *
121    * @param xmlFile The input file to parse.
122    * @return Database populated by <code>xmlFile</code>.
123    */
 
124  0 toggle public Database parseResource(String xmlFile)
125    throws EngineException
126    {
127  0 try
128    {
129    // in case I am missing something, make it obvious
130  0 if (!firstPass)
131    {
132  0 throw new Error("No more double pass");
133    }
134    // check to see if we alread have parsed the file
135  0 if ((alreadyReadFiles != null)
136    && alreadyReadFiles.contains(xmlFile))
137    {
138  0 return database;
139    }
140  0 else if (alreadyReadFiles == null)
141    {
142  0 alreadyReadFiles = new Vector(3, 1);
143    }
144   
145    // remember the file to avoid looping
146  0 alreadyReadFiles.add(xmlFile);
147   
148  0 currentXmlFile = xmlFile;
149   
150  0 SAXParser parser = saxFactory.newSAXParser();
151   
152  0 FileInputStream fileInputStream = null;
153  0 try
154    {
155  0 fileInputStream = new FileInputStream(xmlFile);
156    }
157    catch (FileNotFoundException fnfe)
158    {
159  0 throw new FileNotFoundException
160    (new File(xmlFile).getAbsolutePath());
161    }
162  0 BufferedInputStream bufferedInputStream
163    = new BufferedInputStream(fileInputStream);
164  0 try
165    {
166  0 log.info("Parsing file: '"
167    + (new File(xmlFile)).getName() + "'");
168  0 InputSource is = new InputSource(bufferedInputStream);
169  0 is.setSystemId( new File( xmlFile ).getAbsolutePath() );
170  0 parser.parse(is, this);
171    }
172    finally
173    {
174  0 bufferedInputStream.close();
175    }
176    }
177    catch (SAXParseException e)
178    {
179  0 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  0 throw new EngineException(e);
190    }
191  0 if (!isExternalSchema)
192    {
193  0 firstPass = false;
194    }
195  0 database.doFinalInitialization();
196  0 return database;
197    }
198   
199    /**
200    * EntityResolver implementation. Called by the XML parser
201    *
202    * @param publicId The public identifier of the external entity
203    * @param systemId The system identifier of the external entity
204    * @return an InputSource for the database.dtd file
205    * @see DTDResolver#resolveEntity(String, String)
206    */
 
207  0 toggle public InputSource resolveEntity(String publicId, String systemId)
208    throws SAXException
209    {
210  0 try
211    {
212  0 return new DTDResolver().resolveEntity(publicId, systemId);
213    }
214    catch (Exception e)
215    {
216  0 throw new SAXException(e);
217    }
218    }
219   
220    /**
221    * Handles opening elements of the xml file.
222    *
223    * @param uri
224    * @param localName The local name (without prefix), or the empty string if
225    * Namespace processing is not being performed.
226    * @param rawName The qualified name (with prefix), or the empty string if
227    * qualified names are not available.
228    * @param attributes The specified or defaulted attributes
229    */
 
230  0 toggle public void startElement(String uri, String localName, String rawName,
231    Attributes attributes)
232    throws SAXException
233    {
234  0 try
235    {
236  0 if (rawName.equals("database"))
237    {
238  0 if (isExternalSchema)
239    {
240  0 currentPackage = attributes.getValue("package");
241  0 if (currentPackage == null)
242    {
243  0 currentPackage = defaultPackage;
244    }
245    }
246    else
247    {
248  0 database.loadFromXML(attributes);
249  0 if (database.getPackage() == null)
250    {
251  0 database.setPackage(defaultPackage);
252    }
253    }
254    }
255  0 else if (rawName.equals("external-schema"))
256    {
257  0 String xmlFile = attributes.getValue("filename");
258  0 if (xmlFile.charAt(0) != '/')
259    {
260  0 File f = new File(currentXmlFile);
261  0 xmlFile = new File(f.getParent(), xmlFile).getPath();
262    }
263   
264    // put current state onto the stack
265  0 ParseStackElement.pushState(this);
266   
267  0 isExternalSchema = true;
268   
269  0 parseResource(xmlFile);
270    // get the last state from the stack
271  0 ParseStackElement.popState(this);
272    }
273  0 else if (rawName.equals("domain"))
274    {
275  0 Domain domain = new Domain();
276  0 domain.loadFromXML(attributes, database.getPlatform());
277  0 database.addDomain(domain);
278    }
279  0 else if (rawName.equals("table"))
280    {
281  0 currTable = database.addTable(attributes);
282  0 if (isExternalSchema)
283    {
284  0 currTable.setForReferenceOnly(true);
285  0 currTable.setPackage(currentPackage);
286    }
287    }
288  0 else if (rawName.equals("column"))
289    {
290  0 currColumn = currTable.addColumn(attributes);
291    }
292  0 else if (rawName.equals("inheritance"))
293    {
294  0 currColumn.addInheritance(attributes);
295    }
296  0 else if (rawName.equals("foreign-key"))
297    {
298  0 currFK = currTable.addForeignKey(attributes);
299    }
300  0 else if (rawName.equals("reference"))
301    {
302  0 currFK.addReference(attributes);
303    }
304  0 else if (rawName.equals("index"))
305    {
306  0 currIndex = currTable.addIndex(attributes);
307    }
308  0 else if (rawName.equals("index-column"))
309    {
310  0 currIndex.addColumn(attributes);
311    }
312  0 else if (rawName.equals("unique"))
313    {
314  0 currUnique = currTable.addUnique(attributes);
315    }
316  0 else if (rawName.equals("unique-column"))
317    {
318  0 currUnique.addColumn(attributes);
319    }
320  0 else if (rawName.equals("id-method-parameter"))
321    {
322  0 currTable.addIdMethodParameter(attributes);
323    }
324  0 else if (rawName.equals("option"))
325    {
326  0 setOption(attributes);
327    }
328    }
329    catch (Exception e)
330    {
331  0 throw new SAXException(e);
332    }
333    }
334   
335    /**
336    * Handles closing elements of the xml file.
337    *
338    * @param uri
339    * @param localName The local name (without prefix), or the empty string if
340    * Namespace processing is not being performed.
341    * @param rawName The qualified name (with prefix), or the empty string if
342    * qualified names are not available.
343    */
 
344  0 toggle public void endElement(String uri, String localName, String rawName)
345    throws SAXException
346    {
347  0 if (log.isDebugEnabled())
348    {
349  0 log.debug("endElement(" + uri + ", " + localName + ", "
350    + rawName + ") called");
351    }
352  0 try
353    {
354    // Reset working objects to null to allow option to know
355    // which element it is associated with.
356  0 if (rawName.equals("table"))
357    {
358  0 currTable = null;
359    }
360  0 else if (rawName.equals("column"))
361    {
362  0 currColumn = null;
363    }
364  0 else if (rawName.equals("foreign-key"))
365    {
366  0 currFK = null;
367    }
368  0 else if (rawName.equals("index"))
369    {
370  0 currIndex = null;
371    }
372  0 else if (rawName.equals("unique"))
373    {
374  0 currUnique = null;
375    }
376    }
377    catch (Exception e)
378    {
379  0 throw new SAXException(e);
380    }
381    }
382   
 
383  0 toggle public void setOption(Attributes attributes)
384    {
385    // Look thru supported model elements in reverse order to
386    // find one that this option statement applies to.
387   
388  0 String key = attributes.getValue("key");
389  0 String value = attributes.getValue("value");
390  0 if (currUnique != null)
391    {
392  0 currUnique.addOption(key, value);
393    }
394  0 else if (currIndex != null)
395    {
396  0 currIndex.addOption(key, value);
397    }
398  0 else if (currFK != null)
399    {
400  0 currFK.addOption(key, value);
401    }
402  0 else if (currColumn != null)
403    {
404  0 currColumn.addOption(key, value);
405    }
406  0 else if (currTable != null)
407    {
408  0 currTable.addOption(key, value);
409    }
410    else
411    { // Must be a db level option.
412  0 database.addOption(key, value);
413    }
414    }
415   
416    /**
417    * Handles exception which occur when the xml file is parsed
418    * @param e the exception which occured while parsing
419    * @throws SAXException always
420    */
 
421  0 toggle public void error(SAXParseException e) throws SAXException
422    {
423  0 log.error("Sax parser threw an Exception", e);
424  0 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    * When parsing multiple files that use nested <external-schema> tags we
437    * need to use a stack to remember some values.
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    * @param parser
449    */
 
450  0 toggle public ParseStackElement(XmlToAppData parser)
451    {
452    // remember current state of parent object
453  0 isExternalSchema = parser.isExternalSchema;
454  0 currentPackage = parser.currentPackage;
455  0 currentXmlFile = parser.currentXmlFile;
456  0 firstPass = parser.firstPass;
457   
458    // push the state onto the stack
459  0 parser.parsingStack.push(this);
460    }
461   
462    /**
463    * Removes the top element from the stack and activates the stored state
464    *
465    * @param parser
466    */
 
467  0 toggle public static void popState(XmlToAppData parser)
468    {
469  0 if (!parser.parsingStack.isEmpty())
470    {
471  0 ParseStackElement elem = (ParseStackElement)
472    parser.parsingStack.pop();
473   
474    // activate stored state
475  0 parser.isExternalSchema = elem.isExternalSchema;
476  0 parser.currentPackage = elem.currentPackage;
477  0 parser.currentXmlFile = elem.currentXmlFile;
478  0 parser.firstPass = elem.firstPass;
479    }
480    }
481   
482    /**
483    * Stores the current state on the top of the stack.
484    *
485    * @param parser
486    */
 
487  0 toggle public static void pushState(XmlToAppData parser)
488    {
489  0 new ParseStackElement(parser);
490    }
491    }
492    }