Coverage Report - org.argouml.persistence.SAXParserBase
 
Classes in this File Line Coverage Branch Coverage Complexity
SAXParserBase
0%
0/95
0%
0/34
2.529
 
 1  
 /* $Id: SAXParserBase.java 17832 2010-01-12 19:02:29Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    tfmorris
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2006 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.persistence;
 40  
 
 41  
 import java.io.FileInputStream;
 42  
 import java.io.IOException;
 43  
 import java.io.InputStream;
 44  
 import java.io.Reader;
 45  
 import java.net.URL;
 46  
 
 47  
 import javax.xml.parsers.ParserConfigurationException;
 48  
 import javax.xml.parsers.SAXParser;
 49  
 import javax.xml.parsers.SAXParserFactory;
 50  
 
 51  
 import org.apache.log4j.Logger;
 52  
 import org.xml.sax.Attributes;
 53  
 import org.xml.sax.InputSource;
 54  
 import org.xml.sax.SAXException;
 55  
 import org.xml.sax.helpers.DefaultHandler;
 56  
 
 57  
 /**
 58  
  * @author Jim Holt
 59  
  */
 60  
 
 61  
 abstract class SAXParserBase extends DefaultHandler {
 62  
     /**
 63  
      * Logger.
 64  
      */
 65  0
     private static final Logger LOG = Logger.getLogger(SAXParserBase.class);
 66  
 
 67  
     /**
 68  
      * The constructor.
 69  
      */
 70  0
     public SAXParserBase() {
 71  
         // empty constructor
 72  0
     }
 73  
 
 74  
     ////////////////////////////////////////////////////////////////
 75  
     // static variables
 76  
 
 77  
     /**
 78  
      * Switching this to true gives some extra logging messages.
 79  
      */
 80  
     protected static final boolean DBG = false;
 81  
 
 82  
     /**
 83  
      * This acts as a stack of elements.<p>
 84  
      *
 85  
      * {@link #startElement(String, String, String, Attributes)} places
 86  
      * an item on the stack end {@link #endElement(String, String, String)}
 87  
      * removes it.
 88  
      */
 89  0
     private   static  XMLElement[]  elements      = new XMLElement[100];
 90  
 
 91  
     /**
 92  
      * The number of items actually in use on the elements stack.
 93  
      */
 94  0
     private   static  int           nElements     = 0;
 95  
 
 96  
     /**
 97  
      * This acts as a stack of elements.<p>
 98  
      *
 99  
      * {@link #startElement(String, String, String, Attributes)} places
 100  
      * an item on the stack end {@link #endElement(String, String, String)}
 101  
      * removes it.
 102  
      */
 103  0
     private   static  XMLElement[]  freeElements  = new XMLElement[100];
 104  0
     private   static  int           nFreeElements = 0;
 105  
 
 106  0
     private   static  boolean       stats         = true;
 107  0
     private   static  long          parseTime     = 0;
 108  
 
 109  
     ////////////////////////////////////////////////////////////////
 110  
     // accessors
 111  
 
 112  
     /**
 113  
      * @param s true if statistics have to be shown
 114  
      */
 115  0
     public void    setStats(boolean s) { stats = s; }
 116  
 
 117  
     /**
 118  
      * @return  true if statistics have to be shown
 119  
      */
 120  0
     public boolean getStats()              { return stats; }
 121  
 
 122  
     /**
 123  
      * @return the parsing time
 124  
      */
 125  
     public long getParseTime() {
 126  0
         return parseTime;
 127  
     }
 128  
 
 129  
 
 130  
     /**
 131  
      * @param reader the reader to read
 132  
      * @throws SAXException when parsing xml
 133  
      */
 134  
     public void parse(Reader reader) throws SAXException {
 135  0
         parse(new InputSource(reader));
 136  0
     }
 137  
     
 138  
     /**
 139  
      * @param input the InputSource to read
 140  
      * @throws SAXException when parsing xml
 141  
      */
 142  
     public void parse(InputSource input) throws SAXException {
 143  
 
 144  
         long start, end;
 145  
 
 146  0
         SAXParserFactory factory = SAXParserFactory.newInstance();
 147  0
         factory.setNamespaceAware(false);
 148  0
         factory.setValidating(false);
 149  
 
 150  
         try {
 151  0
             SAXParser parser = factory.newSAXParser();
 152  
 
 153  
             // If we weren't given a system ID, attempt to use the URL for the
 154  
             // JAR that we were loaded from.  (Why? - tfm)
 155  0
             if (input.getSystemId() == null) {
 156  0
                 input.setSystemId(getJarResource("org.argouml.kernel.Project"));
 157  
             }
 158  
 
 159  0
             start = System.currentTimeMillis();
 160  0
             parser.parse(input, this);
 161  0
             end = System.currentTimeMillis();
 162  0
             parseTime = end - start;
 163  0
         } catch (IOException e) {
 164  0
             throw new SAXException(e);
 165  0
         } catch (ParserConfigurationException e) {
 166  0
             throw new SAXException(e);
 167  0
         }
 168  0
         if (stats && LOG.isInfoEnabled()) {
 169  0
             LOG.info("Elapsed time: " + (end - start) + " ms");
 170  
         }
 171  0
     }
 172  
 
 173  
     ////////////////////////////////////////////////////////////////
 174  
     // abstract methods
 175  
 
 176  
     /**
 177  
      * Implement in the concrete class to handle reaching the start tag of
 178  
      * an element of interest.
 179  
      * @param e the element.
 180  
      * @throws SAXException on any error parsing the element.
 181  
      */
 182  
     protected abstract void handleStartElement(XMLElement e)
 183  
         throws SAXException;
 184  
     /**
 185  
      * Implement in the concrete class to handle reaching the end tag of
 186  
      * an element of interest.
 187  
      * @param e the element.
 188  
      * @throws SAXException on any error parsing the element.
 189  
      */
 190  
     protected abstract void handleEndElement(XMLElement e)
 191  
         throws SAXException;
 192  
 
 193  
     ////////////////////////////////////////////////////////////////
 194  
     // non-abstract methods
 195  
 
 196  
     /*
 197  
      * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
 198  
      *         java.lang.String, java.lang.String, org.xml.sax.Attributes)
 199  
      */
 200  
     public void startElement(String uri,
 201  
             String localname,
 202  
             String name,
 203  
             Attributes atts) throws SAXException {
 204  0
         if (isElementOfInterest(name)) {
 205  
 
 206  0
             XMLElement element = createXmlElement(name, atts);
 207  
 
 208  0
             if (LOG.isDebugEnabled()) {
 209  0
                 StringBuffer buf = new StringBuffer();
 210  0
                 buf.append("START: ").append(name).append(' ').append(element);
 211  0
                 for (int i = 0; i < atts.getLength(); i++) {
 212  0
                         buf.append("   ATT: ")
 213  
                         .append(atts.getLocalName(i))
 214  
                             .append(' ')
 215  
                                 .append(atts.getValue(i));
 216  
                 }
 217  0
                 LOG.debug(buf.toString());
 218  
             }
 219  
 
 220  0
             elements[nElements++] = element;
 221  0
             handleStartElement(element);
 222  
         }
 223  0
     }
 224  
 
 225  
     /**
 226  
      * Factory method to return an XMLElement.
 227  
      * This will reuse previously created elements when possible.
 228  
      * @param name The element name.
 229  
      * @param atts The element attributes.
 230  
      * @return the element.
 231  
      */
 232  
     private XMLElement createXmlElement(String name, Attributes atts) {
 233  0
         if (nFreeElements == 0) {
 234  0
             return new XMLElement(name, atts);
 235  
         }
 236  0
         XMLElement e = freeElements[--nFreeElements];
 237  0
         e.setName(name);
 238  0
         e.setAttributes(atts);
 239  0
         e.resetText();
 240  0
         return e;
 241  
     }
 242  
 
 243  
     /*
 244  
      * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
 245  
      *         java.lang.String, java.lang.String)
 246  
      */
 247  
     public void endElement(String uri, String localname, String name)
 248  
         throws SAXException {
 249  0
         if (isElementOfInterest(name)) {
 250  0
             XMLElement e = elements[--nElements];
 251  0
             if (LOG.isDebugEnabled()) {
 252  0
                 StringBuffer buf = new StringBuffer();
 253  0
                 buf.append("END: " + e.getName() + " ["
 254  
                            + e.getText() + "] " + e + "\n");
 255  0
                 for (int i = 0; i < e.getNumAttributes(); i++) {
 256  0
                     buf.append("   ATT: " + e.getAttributeName(i) + " "
 257  
                                + e.getAttributeValue(i) + "\n");
 258  
                 }
 259  0
                 LOG.debug(buf);
 260  
             }
 261  0
             handleEndElement(e);
 262  
         }
 263  0
     }
 264  
 
 265  
     /**
 266  
      * Determine if an element of the given name is of interest to
 267  
      * the parser. The base implementation assumes always true.
 268  
      *
 269  
      * @param name the element name.
 270  
      * @return true if the element name is of interest.
 271  
      */
 272  
     protected boolean isElementOfInterest(String name) {
 273  0
         return true;
 274  
     }
 275  
 
 276  
     // TODO: remove when code below in characters() is removed
 277  
 //    private static final String    RETURNSTRING  = "\n      ";
 278  
     
 279  
     /*
 280  
      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
 281  
      */
 282  
     public void characters(char[] ch, int start, int length)
 283  
         throws SAXException {
 284  
         
 285  0
         elements[nElements - 1].addText(ch, start, length);
 286  
         
 287  
         // TODO: Remove this old implementation after 0.22 if it's
 288  
         // demonstrated that it's not needed. - tfm
 289  
         
 290  
         // Why does the text get added to ALL the elements on the stack? - tfm
 291  
 //        for (int i = 0; i < nElements; i++) {
 292  
 //            XMLElement e = elements[i];
 293  
 //            if (e.length() > 0) {
 294  
 //                // This seems wrong since this method can be called
 295  
 //                // multiple times at the parser's discretion - tfm
 296  
 //                e.addText(RETURNSTRING);
 297  
 //            }
 298  
 //            e.addText(ch, start, length);
 299  
 //        }
 300  0
     }
 301  
 
 302  
 
 303  
     /*
 304  
      * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String,
 305  
      *         java.lang.String)
 306  
      */
 307  
     public InputSource resolveEntity (String publicId, String systemId)
 308  
         throws SAXException {
 309  
         try {
 310  0
             URL testIt = new URL(systemId);
 311  0
             InputSource s = new InputSource(testIt.openStream());
 312  0
             return s;
 313  0
         } catch (Exception e) {
 314  0
             LOG.info("NOTE: Could not open DTD " + systemId
 315  
                     + " due to exception");
 316  
 
 317  0
             String dtdName = systemId.substring(systemId.lastIndexOf('/') + 1);
 318  0
             String dtdPath = "/org/argouml/persistence/" + dtdName;
 319  0
             InputStream is = SAXParserBase.class.getResourceAsStream(dtdPath);
 320  0
             if (is == null) {
 321  
                 try {
 322  0
                     is = new FileInputStream(dtdPath.substring(1));
 323  0
                 } catch (Exception ex) {
 324  0
                     throw new SAXException(e);
 325  0
                 }
 326  
             }
 327  0
             return new InputSource(is);
 328  
         }
 329  
     }
 330  
 
 331  
     /**
 332  
      * @param cls the class
 333  
      * @return the jar
 334  
      */
 335  
     public String getJarResource(String cls) {
 336  
           //e.g:org.argouml.uml.generator.ui.ClassGenerationDialog -> poseidon.jar
 337  0
         String jarFile = "";
 338  0
         String fileSep = System.getProperty("file.separator");
 339  0
         String classFile = cls.replace('.', fileSep.charAt(0)) + ".class";
 340  0
         ClassLoader thisClassLoader = this.getClass().getClassLoader();
 341  0
         URL url = thisClassLoader.getResource(classFile);
 342  0
         if (url != null) {
 343  0
             String urlString = url.getFile();
 344  0
             int idBegin = urlString.indexOf("file:");
 345  0
             int idEnd = urlString.indexOf("!");
 346  0
             if (idBegin > -1 && idEnd > -1 && idEnd > idBegin) {
 347  0
                 jarFile = urlString.substring(idBegin + 5, idEnd);
 348  
             }
 349  
         }
 350  
 
 351  0
         return jarFile;
 352  
     }
 353  
 
 354  
     ////////////////////////////////////////////////////////////////
 355  
     // convenience methods
 356  
 
 357  
     /**
 358  
      * @param e the element
 359  
      */
 360  
     public void ignoreElement(XMLElement e) {
 361  0
         if (LOG.isDebugEnabled()) {
 362  0
             LOG.debug("NOTE: ignoring tag:" + e.getName());
 363  
         }
 364  0
     }
 365  
 
 366  
     /**
 367  
      * @param e the element
 368  
      */
 369  
     public void notImplemented(XMLElement e) {
 370  0
         if (LOG.isDebugEnabled()) {
 371  0
             LOG.debug("NOTE: element not implemented: " + e.getName());
 372  
         }
 373  0
     }
 374  
 } /* end class SAXParserBase */