View Javadoc
1 package org.apache.torque.engine.database.transform; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>. 55 */ 56 57 import java.io.BufferedReader; 58 import java.io.File; 59 import java.io.FileNotFoundException; 60 import java.io.FileReader; 61 import java.util.Stack; 62 import java.util.Vector; 63 64 import javax.xml.parsers.SAXParser; 65 import javax.xml.parsers.SAXParserFactory; 66 67 import org.apache.commons.logging.Log; 68 import org.apache.commons.logging.LogFactory; 69 import org.apache.torque.engine.EngineException; 70 import org.apache.torque.engine.database.model.AppData; 71 import org.apache.torque.engine.database.model.Column; 72 import org.apache.torque.engine.database.model.Database; 73 import org.apache.torque.engine.database.model.ForeignKey; 74 import org.apache.torque.engine.database.model.Index; 75 import org.apache.torque.engine.database.model.Table; 76 import org.apache.torque.engine.database.model.Unique; 77 import org.xml.sax.Attributes; 78 import org.xml.sax.InputSource; 79 import org.xml.sax.SAXException; 80 import org.xml.sax.helpers.DefaultHandler; 81 82 /*** 83 * A Class that is used to parse an input xml schema file and creates an AppData 84 * java structure. 85 * 86 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a> 87 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 88 * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a> 89 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> 90 * @version $Id: XmlToAppData.java,v 1.8 2003/08/25 21:31:22 mpoeschl Exp $ 91 */ 92 public class XmlToAppData extends DefaultHandler 93 { 94 /*** Logging class from commons.logging */ 95 private static Log log = LogFactory.getLog(XmlToAppData.class); 96 97 private AppData app; 98 private Database currDB; 99 private Table currTable; 100 private Column currColumn; 101 private ForeignKey currFK; 102 private Index currIndex; 103 private Unique currUnique; 104 105 private boolean firstPass; 106 private boolean isExternalSchema; 107 private String currentPackage; 108 private String currentXmlFile; 109 private String defaultPackage; 110 111 private static SAXParserFactory saxFactory; 112 113 /*** remember all files we have already parsed to detect looping. */ 114 private Vector alreadyReadFiles; 115 116 /*** this is the stack to store parsing data */ 117 private Stack parsingStack = new Stack(); 118 119 static 120 { 121 saxFactory = SAXParserFactory.newInstance(); 122 saxFactory.setValidating(true); 123 } 124 125 /*** 126 * Creates a new instance for the specified database type. 127 * 128 * @param databaseType The type of database for the application. 129 * @param defaultPackage the default java package used for the om 130 * @param basePropsFilePath The base of the path to the properties 131 * file, including trailing slash. 132 */ 133 public XmlToAppData(String databaseType, String defaultPackage, 134 String basePropsFilePath) 135 { 136 app = new AppData(databaseType, basePropsFilePath); 137 this.defaultPackage = defaultPackage; 138 firstPass = true; 139 } 140 141 /*** 142 * Parses a XML input file and returns a newly created and 143 * populated AppData structure. 144 * 145 * @param xmlFile The input file to parse. 146 * @return AppData populated by <code>xmlFile</code>. 147 */ 148 public AppData parseFile(String xmlFile) 149 throws EngineException 150 { 151 try 152 { 153 // in case I am missing something, make it obvious 154 if (!firstPass) 155 { 156 throw new Error("No more double pass"); 157 } 158 // check to see if we alread have parsed the file 159 if ((alreadyReadFiles != null) 160 && alreadyReadFiles.contains(xmlFile)) 161 { 162 return app; 163 } 164 else if (alreadyReadFiles == null) 165 { 166 alreadyReadFiles = new Vector(3, 1); 167 } 168 169 // remember the file to avoid looping 170 alreadyReadFiles.add(xmlFile); 171 172 currentXmlFile = xmlFile; 173 174 SAXParser parser = saxFactory.newSAXParser(); 175 176 FileReader fr = null; 177 try 178 { 179 fr = new FileReader(xmlFile); 180 } 181 catch (FileNotFoundException fnfe) 182 { 183 throw new FileNotFoundException 184 (new File(xmlFile).getAbsolutePath()); 185 } 186 BufferedReader br = new BufferedReader(fr); 187 try 188 { 189 log.info("Parsing file: '" 190 + (new File(xmlFile)).getName() + "'"); 191 InputSource is = new InputSource(br); 192 parser.parse(is, this); 193 } 194 finally 195 { 196 br.close(); 197 } 198 } 199 catch (Exception e) 200 { 201 throw new EngineException(e); 202 } 203 if (!isExternalSchema) 204 { 205 firstPass = false; 206 } 207 return app; 208 } 209 210 /*** 211 * EntityResolver implementation. Called by the XML parser 212 * 213 * @param publicId The public identifier of the external entity 214 * @param systemId The system identifier of the external entity 215 * @return an InputSource for the database.dtd file 216 * @see org.apache.torque.engine.database.transform.DTDResolver#resolveEntity(String, String) 217 */ 218 public InputSource resolveEntity(String publicId, String systemId) 219 throws SAXException 220 { 221 try 222 { 223 return new DTDResolver().resolveEntity(publicId, systemId); 224 } 225 catch (Exception e) 226 { 227 throw new SAXException(e); 228 } 229 } 230 231 232 /*** 233 * Handles opening elements of the xml file. 234 * 235 * @param uri 236 * @param localName The local name (without prefix), or the empty string if 237 * Namespace processing is not being performed. 238 * @param rawName The qualified name (with prefix), or the empty string if 239 * qualified names are not available. 240 * @param attributes The specified or defaulted attributes 241 */ 242 public void startElement(String uri, String localName, String rawName, 243 Attributes attributes) 244 throws SAXException 245 { 246 try 247 { 248 if (rawName.equals("database")) 249 { 250 if (isExternalSchema) 251 { 252 currentPackage = attributes.getValue("package"); 253 if (currentPackage == null) 254 { 255 currentPackage = defaultPackage; 256 } 257 } 258 else 259 { 260 currDB = app.addDatabase(attributes); 261 if (currDB.getPackage() == null) 262 { 263 currDB.setPackage(defaultPackage); 264 } 265 } 266 } 267 else if (rawName.equals("external-schema")) 268 { 269 String xmlFile = attributes.getValue("filename"); 270 if (xmlFile.charAt(0) != '/') 271 { 272 File f = new File(currentXmlFile); 273 xmlFile = new File(f.getParent(), xmlFile).getPath(); 274 } 275 276 // put current state onto the stack 277 ParseStackElement.pushState(this); 278 279 isExternalSchema = true; 280 281 parseFile(xmlFile); 282 // get the last state from the stack 283 ParseStackElement.popState(this); 284 } 285 else if (rawName.equals("table")) 286 { 287 currTable = currDB.addTable(attributes); 288 if (isExternalSchema) 289 { 290 currTable.setForReferenceOnly(true); 291 currTable.setPackage(currentPackage); 292 } 293 } 294 else if (rawName.equals("column")) 295 { 296 currColumn = currTable.addColumn(attributes); 297 } 298 else if (rawName.equals("inheritance")) 299 { 300 currColumn.addInheritance(attributes); 301 } 302 else if (rawName.equals("foreign-key")) 303 { 304 currFK = currTable.addForeignKey(attributes); 305 } 306 else if (rawName.equals("reference")) 307 { 308 currFK.addReference(attributes); 309 } 310 else if (rawName.equals("index")) 311 { 312 currIndex = currTable.addIndex(attributes); 313 } 314 else if (rawName.equals("index-column")) 315 { 316 currIndex.addColumn(attributes); 317 } 318 else if (rawName.equals("unique")) 319 { 320 currUnique = currTable.addUnique(attributes); 321 } 322 else if (rawName.equals("unique-column")) 323 { 324 currUnique.addColumn(attributes); 325 } 326 else if (rawName.equals("id-method-parameter")) 327 { 328 currTable.addIdMethodParameter(attributes); 329 } 330 } 331 catch (Exception e) 332 { 333 throw new SAXException(e); 334 } 335 } 336 337 /*** 338 * Handles closing elements of the xml file. 339 * 340 * @param uri 341 * @param localName The local name (without prefix), or the empty string if 342 * Namespace processing is not being performed. 343 * @param rawName The qualified name (with prefix), or the empty string if 344 * qualified names are not available. 345 */ 346 public void endElement(String uri, String localName, String rawName) 347 { 348 if (log.isDebugEnabled()) 349 { 350 log.debug("endElement(" + uri + ", " + localName + ", " 351 + rawName + ") called"); 352 } 353 } 354 355 /*** 356 * When parsing multiple files that use nested <external-schema> tags we 357 * need to use a stack to remember some values. 358 */ 359 private static class ParseStackElement 360 { 361 private boolean isExternalSchema; 362 private String currentPackage; 363 private String currentXmlFile; 364 private boolean firstPass; 365 366 /*** 367 * 368 * @param parser 369 */ 370 public ParseStackElement(XmlToAppData parser) 371 { 372 // remember current state of parent object 373 isExternalSchema = parser.isExternalSchema; 374 currentPackage = parser.currentPackage; 375 currentXmlFile = parser.currentXmlFile; 376 firstPass = parser.firstPass; 377 378 // push the state onto the stack 379 parser.parsingStack.push(this); 380 } 381 382 /*** 383 * Removes the top element from the stack and activates the stored state 384 * 385 * @param parser 386 */ 387 public static void popState(XmlToAppData parser) 388 { 389 if (!parser.parsingStack.isEmpty()) 390 { 391 ParseStackElement elem = (ParseStackElement) 392 parser.parsingStack.pop(); 393 394 // activate stored state 395 parser.isExternalSchema = elem.isExternalSchema; 396 parser.currentPackage = elem.currentPackage; 397 parser.currentXmlFile = elem.currentXmlFile; 398 parser.firstPass = elem.firstPass; 399 } 400 } 401 402 /*** 403 * Stores the current state on the top of the stack. 404 * 405 * @param parser 406 */ 407 public static void pushState(XmlToAppData parser) 408 { 409 new ParseStackElement(parser); 410 } 411 } 412 }

This page was automatically generated by Maven