Coverage report

  %line %branch
org.apache.torque.engine.database.transform.XmlToAppData$ParseStackElement
0% 
0% 

 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.xml.sax.Attributes;
 43  
 import org.xml.sax.InputSource;
 44  
 import org.xml.sax.SAXException;
 45  
 import org.xml.sax.SAXParseException;
 46  
 import org.xml.sax.helpers.DefaultHandler;
 47  
 
 48  
 /**
 49  
  * A Class that is used to parse an input xml schema file and creates a Database
 50  
  * java structure.
 51  
  *
 52  
  * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
 53  
  * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
 54  
  * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
 55  
  * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
 56  
  * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
 57  
  * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a>
 58  
  * @version $Id: XmlToAppData.java 473814 2006-11-11 22:30:30Z tv $
 59  
  */
 60  
 public class XmlToAppData extends DefaultHandler
 61  
 {
 62  
     /** Logging class from commons.logging */
 63  
     private static Log log = LogFactory.getLog(XmlToAppData.class);
 64  
 
 65  
     private Database database;
 66  
     private Table currTable;
 67  
     private Column currColumn;
 68  
     private ForeignKey currFK;
 69  
     private Index currIndex;
 70  
     private Unique currUnique;
 71  
 
 72  
     private boolean firstPass;
 73  
     private boolean isExternalSchema;
 74  
     private String currentPackage;
 75  
     private String currentXmlFile;
 76  
     private String defaultPackage;
 77  
 
 78  
     private static SAXParserFactory saxFactory;
 79  
 
 80  
     /** remember all files we have already parsed to detect looping. */
 81  
     private Vector alreadyReadFiles;
 82  
 
 83  
     /** this is the stack to store parsing data */
 84  
     private Stack parsingStack = new Stack();
 85  
 
 86  
     static
 87  
     {
 88  
         saxFactory = SAXParserFactory.newInstance();
 89  
         saxFactory.setValidating(true);
 90  
     }
 91  
 
 92  
     /**
 93  
      * Creates a new instance for the specified database type.
 94  
      *
 95  
      * @param databaseType The type of database for the application.
 96  
      */
 97  
     public XmlToAppData(String databaseType)
 98  
     {
 99  
         database = new Database(databaseType);
 100  
         firstPass = true;
 101  
     }
 102  
 
 103  
     /**
 104  
      * Creates a new instance for the specified database type.
 105  
      *
 106  
      * @param databaseType The type of database for the application.
 107  
      * @param defaultPackage the default java package used for the om
 108  
      */
 109  
     public XmlToAppData(String databaseType, String defaultPackage)
 110  
     {
 111  
         database = new Database(databaseType);
 112  
         this.defaultPackage = defaultPackage;
 113  
         firstPass = true;
 114  
     }
 115  
 
 116  
     /**
 117  
      * Parses a XML input file and returns a newly created and
 118  
      * populated Database structure.
 119  
      *
 120  
      * @param xmlFile The input file to parse.
 121  
      * @return Database populated by <code>xmlFile</code>.
 122  
      */
 123  
     public Database parseFile(String xmlFile)
 124  
             throws EngineException
 125  
     {
 126  
         try
 127  
         {
 128  
             // in case I am missing something, make it obvious
 129  
             if (!firstPass)
 130  
             {
 131  
                 throw new Error("No more double pass");
 132  
             }
 133  
             // check to see if we alread have parsed the file
 134  
             if ((alreadyReadFiles != null)
 135  
                     && alreadyReadFiles.contains(xmlFile))
 136  
             {
 137  
                 return database;
 138  
             }
 139  
             else if (alreadyReadFiles == null)
 140  
             {
 141  
                 alreadyReadFiles = new Vector(3, 1);
 142  
             }
 143  
 
 144  
             // remember the file to avoid looping
 145  
             alreadyReadFiles.add(xmlFile);
 146  
 
 147  
             currentXmlFile = xmlFile;
 148  
 
 149  
             SAXParser parser = saxFactory.newSAXParser();
 150  
 
 151  
             FileInputStream fileInputStream = null;
 152  
             try
 153  
             {
 154  
                 fileInputStream = new FileInputStream(xmlFile);
 155  
             }
 156  
             catch (FileNotFoundException fnfe)
 157  
             {
 158  
                 throw new FileNotFoundException
 159  
                     (new File(xmlFile).getAbsolutePath());
 160  
             }
 161  
             BufferedInputStream bufferedInputStream
 162  
                     = new BufferedInputStream(fileInputStream);
 163  
             try
 164  
             {
 165  
                 log.info("Parsing file: '"
 166  
                         + (new File(xmlFile)).getName() + "'");
 167  
                 InputSource is = new InputSource(bufferedInputStream);
 168  
                 parser.parse(is, this);
 169  
             }
 170  
             finally
 171  
             {
 172  
                 bufferedInputStream.close();
 173  
             }
 174  
         }
 175  
         catch (SAXParseException e)
 176  
         {
 177  
             throw new EngineException("Sax error on line "
 178  
                         + e.getLineNumber()
 179  
                         + " column "
 180  
                         + e.getColumnNumber()
 181  
                         + " : "
 182  
                         + e.getMessage(),
 183  
                     e);
 184  
         }
 185  
         catch (Exception e)
 186  
         {
 187  
             throw new EngineException(e);
 188  
         }
 189  
         if (!isExternalSchema)
 190  
         {
 191  
             firstPass = false;
 192  
         }
 193  
         database.doFinalInitialization();
 194  
         return database;
 195  
     }
 196  
 
 197  
     /**
 198  
      * EntityResolver implementation. Called by the XML parser
 199  
      *
 200  
      * @param publicId The public identifier of the external entity
 201  
      * @param systemId The system identifier of the external entity
 202  
      * @return an InputSource for the database.dtd file
 203  
      * @see DTDResolver#resolveEntity(String, String)
 204  
      */
 205  
     public InputSource resolveEntity(String class="keyword">publicId, String systemId)
 206  
             throws SAXException
 207  
     {
 208  
         try
 209  
         {
 210  
             return new DTDResolver().resolveEntity(publicId, systemId);
 211  
         }
 212  
         catch (Exception e)
 213  
         {
 214  
             throw new SAXException(e);
 215  
         }
 216  
     }
 217  
 
 218  
     /**
 219  
      * Handles opening elements of the xml file.
 220  
      *
 221  
      * @param uri
 222  
      * @param localName The local name (without prefix), or the empty string if
 223  
      *         Namespace processing is not being performed.
 224  
      * @param rawName The qualified name (with prefix), or the empty string if
 225  
      *         qualified names are not available.
 226  
      * @param attributes The specified or defaulted attributes
 227  
      */
 228  
     public void startElement(String uri, String localName, String rawName,
 229  
                              Attributes attributes)
 230  
             throws SAXException
 231  
     {
 232  
         try
 233  
         {
 234  
             if (rawName.equals("database"))
 235  
             {
 236  
                 if (isExternalSchema)
 237  
                 {
 238  
                     currentPackage = attributes.getValue("package");
 239  
                     if (currentPackage == null)
 240  
                     {
 241  
                         currentPackage = defaultPackage;
 242  
                     }
 243  
                 }
 244  
                 else
 245  
                 {
 246  
                     database.loadFromXML(attributes);
 247  
                     if (database.getPackage() == null)
 248  
                     {
 249  
                         database.setPackage(defaultPackage);
 250  
                     }
 251  
                 }
 252  
             }
 253  
             else if (rawName.equals("external-schema"))
 254  
             {
 255  
                 String xmlFile = attributes.getValue("filename");
 256  
                 if (xmlFile.charAt(0) != '/')
 257  
                 {
 258  
                     File f = new File(currentXmlFile);
 259  
                     xmlFile = new File(f.getParent(), xmlFile).getPath();
 260  
                 }
 261  
 
 262  
                 // put current state onto the stack
 263  
                 ParseStackElement.pushState(this);
 264  
 
 265  
                 isExternalSchema = true;
 266  
 
 267  
                 parseFile(xmlFile);
 268  
                 // get the last state from the stack
 269  
                 ParseStackElement.popState(this);
 270  
             }
 271  
             else if (rawName.equals("domain"))
 272  
             {
 273  
                 Domain domain = new Domain();
 274  
                 domain.loadFromXML(attributes, database.getPlatform());
 275  
                 database.addDomain(domain);
 276  
             }
 277  
             else if (rawName.equals("table"))
 278  
             {
 279  
                 currTable = database.addTable(attributes);
 280  
                 if (isExternalSchema)
 281  
                 {
 282  
                     currTable.setForReferenceOnly(true);
 283  
                     currTable.setPackage(currentPackage);
 284  
                 }
 285  
             }
 286  
             else if (rawName.equals("column"))
 287  
             {
 288  
                 currColumn = currTable.addColumn(attributes);
 289  
             }
 290  
             else if (rawName.equals("inheritance"))
 291  
             {
 292  
                 currColumn.addInheritance(attributes);
 293  
             }
 294  
             else if (rawName.equals("foreign-key"))
 295  
             {
 296  
                 currFK = currTable.addForeignKey(attributes);
 297  
             }
 298  
             else if (rawName.equals("reference"))
 299  
             {
 300  
                 currFK.addReference(attributes);
 301  
             }
 302  
             else if (rawName.equals("index"))
 303  
             {
 304  
                 currIndex = currTable.addIndex(attributes);
 305  
             }
 306  
             else if (rawName.equals("index-column"))
 307  
             {
 308  
                 currIndex.addColumn(attributes);
 309  
             }
 310  
             else if (rawName.equals("unique"))
 311  
             {
 312  
                 currUnique = currTable.addUnique(attributes);
 313  
             }
 314  
             else if (rawName.equals("unique-column"))
 315  
             {
 316  
                 currUnique.addColumn(attributes);
 317  
             }
 318  
             else if (rawName.equals("id-method-parameter"))
 319  
             {
 320  
                 currTable.addIdMethodParameter(attributes);
 321  
             }
 322  
             else if (rawName.equals("option"))
 323  
             {
 324  
                 setOption(attributes);
 325  
             }
 326  
         }
 327  
         catch (Exception e)
 328  
         {
 329  
             throw new SAXException(e);
 330  
         }
 331  
     }
 332  
 
 333  
     /**
 334  
      * Handles closing elements of the xml file.
 335  
      *
 336  
      * @param uri
 337  
      * @param localName The local name (without prefix), or the empty string if
 338  
      *         Namespace processing is not being performed.
 339  
      * @param rawName The qualified name (with prefix), or the empty string if
 340  
      *         qualified names are not available.
 341  
      */
 342  
     public void endElement(String uri, String localName, String rawName)
 343  
         throws SAXException
 344  
     {
 345  
         if (log.isDebugEnabled())
 346  
         {
 347  
             log.debug("endElement(" + uri + ", " + localName + ", "
 348  
                     + rawName + ") called");
 349  
         }
 350  
         try
 351  
         {
 352  
             // Reset working objects to null to allow option to know
 353  
             // which element it is associated with.
 354  
             if (rawName.equals("table"))
 355  
             {
 356  
                 currTable = null;
 357  
             }
 358  
             else if (rawName.equals("column"))
 359  
             {
 360  
                 currColumn = null;
 361  
             }
 362  
             else if (rawName.equals("foreign-key"))
 363  
             {
 364  
                 currFK = null;
 365  
             }
 366  
             else if (rawName.equals("index"))
 367  
             {
 368  
                 currIndex = null;
 369  
             }
 370  
             else if (rawName.equals("unique"))
 371  
             {
 372  
                 currUnique = null;
 373  
             }
 374  
         }
 375  
         catch (Exception e)
 376  
         {
 377  
             throw new SAXException(e);
 378  
         }
 379  
     }
 380  
 
 381  
     public void setOption(Attributes attributes)
 382  
     {
 383  
         // Look thru supported model elements in reverse order to
 384  
         // find one that this option statement applies to.
 385  
 
 386  
         String key = attributes.getValue("key");
 387  
         String value = attributes.getValue("value");
 388  
         if (currUnique != null)
 389  
         {
 390  
             currUnique.addOption(key, value);
 391  
         }
 392  
         else if (currIndex != null)
 393  
         {
 394  
             currIndex.addOption(key, value);
 395  
         }
 396  
         else if (currFK != null)
 397  
         {
 398  
             currFK.addOption(key, value);
 399  
         }
 400  
         else if (currColumn != null)
 401  
         {
 402  
             currColumn.addOption(key, value);
 403  
         }
 404  
         else if (currTable != null)
 405  
         {
 406  
             currTable.addOption(key, value);
 407  
         }
 408  
         else
 409  
         {                            // Must be a db level option.
 410  
             database.addOption(key, value);
 411  
         }
 412  
     }
 413  
 
 414  
     /**
 415  
      * Handles exception which occur when the xml file is parsed
 416  
      * @param e the exception which occured while parsing
 417  
      * @throws SAXException always
 418  
      */
 419  
     public void error(SAXParseException e) throws SAXException
 420  
     {
 421  
         log.error("Sax parser threw an Exception", e);
 422  
         throw new SAXException(
 423  
                 "Error while parsing "
 424  
                 + currentXmlFile
 425  
                 + " at line "
 426  
                 + e.getLineNumber()
 427  
                 + " column "
 428  
                 + e.getColumnNumber()
 429  
                 + " : "
 430  
                 + e.getMessage());
 431  
     }
 432  
 
 433  
     /**
 434  
      * When parsing multiple files that use nested <external-schema> tags we
 435  
      * need to use a stack to remember some values.
 436  
      */
 437  
     private static class ParseStackElement
 438  
     {
 439  
         private boolean isExternalSchema;
 440  
         private String currentPackage;
 441  
         private String currentXmlFile;
 442  
         private boolean firstPass;
 443  
 
 444  
         /**
 445  
          *
 446  
          * @param parser
 447  
          */
 448  
         public ParseStackElement(XmlToAppData parser)
 449  0
         {
 450  
             // remember current state of parent object
 451  0
             isExternalSchema = parser.isExternalSchema;
 452  0
             currentPackage = parser.currentPackage;
 453  0
             currentXmlFile = parser.currentXmlFile;
 454  0
             firstPass = parser.firstPass;
 455  
 
 456  
             // push the state onto the stack
 457  0
             parser.parsingStack.push(this);
 458  0
         }
 459  
 
 460  
         /**
 461  
          * Removes the top element from the stack and activates the stored state
 462  
          *
 463  
          * @param parser
 464  
          */
 465  
         public static void popState(XmlToAppData parser)
 466  
         {
 467  0
             if (!parser.parsingStack.isEmpty())
 468  
             {
 469  0
                 ParseStackElement elem = (ParseStackElement)
 470  
                         parser.parsingStack.pop();
 471  
 
 472  
                 // activate stored state
 473  0
                 parser.isExternalSchema = elem.isExternalSchema;
 474  0
                 parser.currentPackage = elem.currentPackage;
 475  0
                 parser.currentXmlFile = elem.currentXmlFile;
 476  0
                 parser.firstPass = elem.firstPass;
 477  
             }
 478  0
         }
 479  
 
 480  
         /**
 481  
          * Stores the current state on the top of the stack.
 482  
          *
 483  
          * @param parser
 484  
          */
 485  
         public static void pushState(XmlToAppData parser)
 486  
         {
 487  0
             new ParseStackElement(parser);
 488  0
         }
 489  
     }
 490  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.