Clover coverage report - Drools - 2.0-rc2
Coverage timestamp: Wed May 11 2005 07:12:26 BST
file stats: LOC: 1,022   Methods: 38
NCLOC: 649   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
RuleSetReader.java 67.8% 68.7% 65.8% 68.2%
coverage coverage
 1    package org.drools.io;
 2   
 3    /*
 4    * $Id: RuleSetReader.java,v 1.46.2.8 2005/05/02 01:51:50 mproctor Exp $
 5    *
 6    * Copyright 2001-2003 (C) The Werken Company. All Rights Reserved.
 7    *
 8    * Redistribution and use of this software and associated documentation
 9    * ("Software"), with or without modification, are permitted provided that the
 10    * following conditions are met:
 11    *
 12    * 1. Redistributions of source code must retain copyright statements and
 13    * notices. Redistributions must also contain a copy of this document.
 14    *
 15    * 2. Redistributions in binary form must reproduce the above copyright notice,
 16    * this list of conditions and the following disclaimer in the documentation
 17    * and/or other materials provided with the distribution.
 18    *
 19    * 3. The name "drools" must not be used to endorse or promote products derived
 20    * from this Software without prior written permission of The Werken Company.
 21    * For written permission, please contact bob@werken.com.
 22    *
 23    * 4. Products derived from this Software may not be called "drools" nor may
 24    * "drools" appear in their names without prior written permission of The Werken
 25    * Company. "drools" is a trademark of The Werken Company.
 26    *
 27    * 5. Due credit should be given to The Werken Company. (http://werken.com/)
 28    *
 29    * THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS ``AS IS''
 30    * AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 31    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 32    * ARE DISCLAIMED. IN NO EVENT SHALL THE WERKEN COMPANY OR ITS CONTRIBUTORS BE
 33    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 34    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 35    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 36    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 37    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 38    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 39    * POSSIBILITY OF SUCH DAMAGE.
 40    *
 41    */
 42   
 43    import java.io.BufferedInputStream;
 44    import java.io.FileInputStream;
 45    import java.io.IOException;
 46    import java.io.InputStream;
 47    import java.io.Reader;
 48    import java.net.URL;
 49    import java.text.MessageFormat;
 50    import java.util.HashMap;
 51    import java.util.Iterator;
 52    import java.util.LinkedList;
 53    import java.util.ListIterator;
 54    import java.util.Map;
 55    import java.util.Set;
 56   
 57    import javax.xml.parsers.ParserConfigurationException;
 58    import javax.xml.parsers.SAXParser;
 59    import javax.xml.parsers.SAXParserFactory;
 60   
 61    import org.drools.rule.Rule;
 62    import org.drools.rule.RuleSet;
 63    import org.drools.smf.Configuration;
 64    import org.drools.smf.DefaultConfiguration;
 65    import org.drools.smf.DefaultSemanticsRepository;
 66    import org.drools.smf.NoSuchSemanticModuleException;
 67    import org.drools.smf.SemanticModule;
 68    import org.drools.smf.SemanticsRepository;
 69    import org.drools.spi.RuleBaseContext;
 70    import org.xml.sax.Attributes;
 71    import org.xml.sax.InputSource;
 72    import org.xml.sax.Locator;
 73    import org.xml.sax.SAXException;
 74    import org.xml.sax.SAXNotRecognizedException;
 75    import org.xml.sax.SAXParseException;
 76    import org.xml.sax.helpers.DefaultHandler;
 77   
 78    /**
 79    * <code>RuleSet</code> loader.
 80    *
 81    * @author <a href="mailto:bob@werken.com">bob mcwhirter </a>
 82    *
 83    * @version $Id: RuleSetReader.java,v 1.46.2.8 2005/05/02 01:51:50 mproctor Exp $
 84    */
 85    public class RuleSetReader extends DefaultHandler
 86    {
 87    // ----------------------------------------------------------------------
 88    // Constants
 89    // ----------------------------------------------------------------------
 90   
 91    /** Namespace URI for the general tags. */
 92    public static final String RULES_NAMESPACE_URI = "http://drools.org/rules";
 93   
 94    private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
 95   
 96    private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
 97   
 98    // ----------------------------------------------------------------------
 99    // Instance members
 100    // ----------------------------------------------------------------------
 101    /** SAX parser. */
 102    private SAXParser parser;
 103   
 104    /** isValidating */
 105    private boolean isValidating = true;
 106   
 107    /** Locator for errors. */
 108    private Locator locator;
 109   
 110    /** Repository of semantic modules. */
 111    private SemanticsRepository repo;
 112    // private Map repo;
 113   
 114    /** Stack of configurations. */
 115    private LinkedList configurationStack;
 116   
 117    /** Current configuration text. */
 118    private StringBuffer characters;
 119   
 120    private Map handlers;
 121   
 122    private boolean lastWasEndElement;
 123   
 124    private LinkedList parents;
 125   
 126    private Object peer;
 127   
 128    private Object current;
 129   
 130    private RuleSet ruleSet;
 131   
 132    private RuleBaseContext factoryContext;
 133   
 134    private boolean inHandledRuleSubElement;
 135   
 136    private MessageFormat message = new MessageFormat( "({0}: {1}, {2}): {3}" );
 137   
 138    // ----------------------------------------------------------------------
 139    // Constructors
 140    // ----------------------------------------------------------------------
 141   
 142    /**
 143    * Construct.
 144    *
 145    * <p>
 146    * Uses the default JAXP SAX parser and the default classpath-based
 147    * <code>DefaultSemanticModule</code>.
 148    * </p>
 149    */
 150  66 public RuleSetReader()
 151    {
 152    // init
 153  66 this.configurationStack = new LinkedList( );
 154  66 this.parents = new LinkedList( );
 155   
 156  66 this.handlers = new HashMap( );
 157  66 this.handlers.put( "RuleSet",
 158    new RuleSetHandler( this ) );
 159  66 this.handlers.put( "ImportEntry",
 160    new ImportHandler( this ) );
 161  66 this.handlers.put( "ApplicationData",
 162    new ApplicationDataHandler( this ) );
 163  66 this.handlers.put( "Functions",
 164    new FunctionsHandler( this ) );
 165  66 this.handlers.put( "Rule",
 166    new RuleHandler( this ) );
 167  66 this.handlers.put( "Parameter",
 168    new ParameterHandler( this ) );
 169    // localNameMap.put( "declaration", new DeclarationHandler( this ) );
 170  66 this.handlers.put( "ObjectType",
 171    new ObjectTypeHandler( this ) );
 172  66 this.handlers.put( "Condition",
 173    new ConditionHandler( this ) );
 174  66 this.handlers.put( "Duration",
 175    new DurationHandler( this ) );
 176  66 this.handlers.put( "Consequence",
 177    new ConsequenceHandler( this ) );
 178   
 179    }
 180   
 181    /**
 182    * Construct.
 183    *
 184    * <p>
 185    * Uses the default classpath-based <code>DefaultSemanticModule</code>.
 186    * </p>
 187    *
 188    * @param parser
 189    * The SAX parser.
 190    */
 191  0 public RuleSetReader(SAXParser parser)
 192    {
 193  0 this( );
 194  0 this.parser = parser;
 195    }
 196   
 197    /**
 198    * Construct.
 199    *
 200    * @param repo
 201    * The semantics repository.
 202    */
 203  2 public RuleSetReader(SemanticsRepository repo)
 204    {
 205  2 this( );
 206  2 this.repo = repo;
 207    }
 208   
 209    /**
 210    * Construct.
 211    *
 212    * @param factoryContext
 213    */
 214  0 public RuleSetReader(RuleBaseContext factoryContext)
 215    {
 216  0 this( );
 217  0 this.factoryContext = factoryContext;
 218    }
 219   
 220    /**
 221    * Construct.
 222    *
 223    * @param repo
 224    * The semantics repository.
 225    * @param parser
 226    * The SAX parser.
 227    */
 228  0 public RuleSetReader(SemanticsRepository repo,
 229    SAXParser parser)
 230    {
 231  0 this( parser );
 232  0 this.repo = repo;
 233    }
 234   
 235    /**
 236    * Construct.
 237    *
 238    * @param repo
 239    * The semantics repository.
 240    */
 241  0 public RuleSetReader(SemanticsRepository repo,
 242    RuleBaseContext context)
 243    {
 244  0 this( );
 245  0 this.repo = repo;
 246  0 this.factoryContext = context;
 247    }
 248   
 249    /**
 250    * Construct.
 251    *
 252    * @param parser
 253    *
 254    * @param repo
 255    * The semantics repository.
 256    */
 257  0 public RuleSetReader(SAXParser parser,
 258    SemanticsRepository repo)
 259    {
 260  0 this( );
 261  0 this.parser = parser;
 262  0 this.repo = repo;
 263    }
 264   
 265    /**
 266    * Construct.
 267    *
 268    * @param parser
 269    * @param context
 270    */
 271  0 public RuleSetReader(SAXParser parser,
 272    RuleBaseContext context)
 273    {
 274  0 this( );
 275  0 this.parser = parser;
 276  0 this.factoryContext = context;
 277    }
 278   
 279    /**
 280    * Construct.
 281    *
 282    * @param repo
 283    * The semantics repository.
 284    * @param parser
 285    * The SAX parser.
 286    */
 287  0 public RuleSetReader(SemanticsRepository repo,
 288    SAXParser parser,
 289    RuleBaseContext context)
 290    {
 291  0 this( parser );
 292  0 this.repo = repo;
 293  0 this.factoryContext = context;
 294    }
 295   
 296    // ----------------------------------------------------------------------
 297    // Instance methods
 298    // ----------------------------------------------------------------------
 299   
 300    /**
 301    * Read a <code>RuleSet</code> from a <code>URL</code>.
 302    *
 303    * @param url
 304    * The rule-set URL.
 305    *
 306    * @return The rule-set.
 307    */
 308  2 public RuleSet read(URL url) throws SAXException,
 309    IOException
 310    {
 311  2 return read( new InputSource( url.toExternalForm( ) ) );
 312    }
 313   
 314    /**
 315    * Read a <code>RuleSet</code> from a <code>Reader</code>.
 316    *
 317    * @param reader
 318    * The reader containing the rule-set.
 319    *
 320    * @return The rule-set.
 321    */
 322  43 public RuleSet read(Reader reader) throws SAXException,
 323    IOException
 324    {
 325  43 return read( new InputSource( reader ) );
 326    }
 327   
 328    /**
 329    * Read a <code>RuleSet</code> from an <code>InputStream</code>.
 330    *
 331    * @param inputStream
 332    * The input-stream containing the rule-set.
 333    *
 334    * @return The rule-set.
 335    */
 336  19 public RuleSet read(InputStream inputStream) throws SAXException,
 337    IOException
 338    {
 339  19 return read( new InputSource( inputStream ) );
 340    }
 341   
 342    /**
 343    * Read a <code>RuleSet</code> from a URL.
 344    *
 345    * @param url
 346    * The rule-set URL.
 347    *
 348    * @return The rule-set.
 349    */
 350  0 public RuleSet read(String url) throws SAXException,
 351    IOException
 352    {
 353  0 return read( new InputSource( url ) );
 354    }
 355   
 356    /**
 357    * Read a <code>RuleSet</code> from an <code>InputSource</code>.
 358    *
 359    * @param in
 360    * The rule-set input-source.
 361    *
 362    * @return The rule-set.
 363    */
 364  64 public RuleSet read(InputSource in) throws SAXException,
 365    IOException
 366    {
 367  64 SAXParser localParser = null;
 368  64 if ( this.parser == null )
 369    {
 370  64 SAXParserFactory factory = SAXParserFactory.newInstance( );
 371   
 372  64 factory.setNamespaceAware( true );
 373   
 374  64 String isValidatingString = System.getProperty( "drools.schema.validating" );
 375  64 if ( System.getProperty( "drools.schema.validating" ) != null )
 376    {
 377  0 this.isValidating = Boolean.getBoolean( "drools.schema.validating" );
 378    }
 379   
 380  64 if ( this.isValidating == true )
 381    {
 382  64 factory.setValidating( true );
 383  64 try
 384    {
 385  64 localParser = factory.newSAXParser( );
 386    }
 387    catch ( ParserConfigurationException e )
 388    {
 389  0 throw new RuntimeException( e.getMessage( ) );
 390    }
 391   
 392  64 try
 393    {
 394  64 localParser.setProperty( JAXP_SCHEMA_LANGUAGE,
 395    W3C_XML_SCHEMA );
 396    }
 397    catch ( SAXNotRecognizedException e )
 398    {
 399  0 boolean hideWarnings = Boolean.getBoolean( "drools.schema.hidewarnings" );
 400  0 if ( !hideWarnings )
 401    {
 402  0 System.err.println( "Your SAX parser is not JAXP 1.2 compliant - turning off validation." );
 403    }
 404  0 localParser = null;
 405    }
 406    }
 407   
 408  64 if ( localParser == null )
 409    {
 410    // not jaxp1.2 compliant so turn off validation
 411  0 try
 412    {
 413  0 this.isValidating = false;
 414  0 factory.setValidating( this.isValidating );
 415  0 localParser = factory.newSAXParser( );
 416    }
 417    catch ( ParserConfigurationException e )
 418    {
 419  0 throw new RuntimeException( e.getMessage( ) );
 420    }
 421    }
 422    }
 423    else
 424    {
 425  0 localParser = this.parser;
 426    }
 427   
 428  64 if ( !localParser.isNamespaceAware( ) )
 429    {
 430  0 throw new RuntimeException( "parser must be namespace-aware" );
 431    }
 432   
 433  64 if ( this.repo == null )
 434    {
 435  64 try
 436    {
 437  64 this.repo = DefaultSemanticsRepository.getInstance( );
 438    }
 439    catch ( Exception e )
 440    {
 441  0 throw new SAXException( "Unable to reference a Semantics Repository:\n" + e.getMessage() );
 442    }
 443    }
 444   
 445  64 localParser.parse( in,
 446    this );
 447   
 448  63 return this.ruleSet;
 449    }
 450   
 451  0 public SemanticsRepository getSemanticsRepository()
 452    {
 453  0 return this.repo;
 454    }
 455   
 456  66 void setRuleSet(RuleSet ruleSet)
 457    {
 458  66 this.ruleSet = ruleSet;
 459    }
 460   
 461  375 public RuleSet getRuleSet()
 462    {
 463  375 return this.ruleSet;
 464    }
 465   
 466  519 public RuleBaseContext getFactoryContext()
 467    {
 468  519 return this.factoryContext;
 469    }
 470   
 471    /**
 472    * @see org.xml.sax.ContentHandler
 473    */
 474  0 public void setLocator(Locator locator)
 475    {
 476  0 this.locator = locator;
 477    }
 478   
 479    /**
 480    * Get the <code>Locator</code>.
 481    *
 482    * @return The locator.
 483    */
 484  1 public Locator getLocator()
 485    {
 486  1 return this.locator;
 487    }
 488   
 489  66 public void startDocument()
 490    {
 491  66 this.isValidating = true;
 492  66 this.ruleSet = null;
 493  66 this.current = null;
 494  66 this.peer = null;
 495  66 this.lastWasEndElement = false;
 496  66 this.parents.clear( );
 497  66 this.characters = null;
 498  66 this.configurationStack.clear( );
 499  66 if ( this.factoryContext == null )
 500    {
 501  66 this.factoryContext = new RuleBaseContext( );
 502    }
 503   
 504    // now assign the smf classloader so smf implementations can access it
 505  66 ClassLoader classLoader = (ClassLoader) this.factoryContext.get( "smf-classLoader" );
 506  66 if ( classLoader == null )
 507    {
 508  66 this.factoryContext.put( "smf-classLoader",
 509    repo.getSemanticModuleClassLoader( ) );
 510    }
 511    }
 512   
 513    /**
 514    * @param uri
 515    * @param localName
 516    * @param qname
 517    * @param attrs
 518    * @throws SAXException
 519    * @see org.xml.sax.ContentHandler
 520    *
 521    * @todo: better way to manage unhandled elements
 522    */
 523  683 public void startElement(String uri,
 524    String localName,
 525    String qname,
 526    Attributes attrs) throws SAXException
 527    {
 528    // going down so no peer
 529  683 if ( !this.lastWasEndElement )
 530    {
 531  372 this.peer = null;
 532    }
 533   
 534  683 Handler handler = getHandler( uri,
 535    localName );
 536   
 537  683 if ( ( handler != null ) && ( !this.parents.isEmpty() && this.parents.getLast() instanceof Rule ) )
 538    {
 539  344 this.inHandledRuleSubElement = true;
 540    }
 541   
 542  683 if ( handler == null )
 543    {
 544  0 if ( ( ( this.inHandledRuleSubElement == false) && ( this.parents.getLast( ) instanceof Rule ) )
 545    || ( this.parents.getLast( ) instanceof RuleSet ) )
 546    {
 547   
 548    /* see if the uri is registered */
 549  0 try
 550    {
 551  0 this.repo.lookupSemanticModule( uri );
 552    /* uri is registered, but the element is not mapped correctly to a handler */
 553  0 throw new SAXParseException( "unknown tag '" + localName + "' in namespace '" + uri + "'",
 554    getLocator( ) );
 555    }
 556    catch ( NoSuchSemanticModuleException e )
 557    {
 558    /* uri is not registered, so incorrect uri, missing drools.conf or classloader issues*/
 559  0 throw new SAXParseException( "no semantic module for namespace '" + uri + "' (" + localName + ")",
 560    getLocator() );
 561    }
 562   
 563   
 564   
 565    }
 566    // no handler so build up the configuration
 567  0 startConfiguration( localName,
 568    attrs );
 569  0 return;
 570    }
 571   
 572  683 validate( uri,
 573    localName,
 574    handler );
 575   
 576  683 Object node = handler.start( uri,
 577    localName,
 578    attrs );
 579   
 580  682 if ( node != null )
 581    {
 582  308 this.parents.add( node );
 583  308 this.current = node;
 584    }
 585  682 this.lastWasEndElement = false;
 586    }
 587   
 588    /**
 589    * @param uri
 590    * @param localName
 591    * @param qname
 592    * @throws SAXException
 593    * @see org.xml.sax.ContentHandler
 594    */
 595  681 public void endElement(String uri,
 596    String localName,
 597    String qname) throws SAXException
 598    {
 599  681 Handler handler = getHandler( uri,
 600    localName );
 601   
 602  681 if ( ( handler != null ) && ( !this.parents.isEmpty() && this.parents.getLast() instanceof Rule ) )
 603    {
 604  258 this.inHandledRuleSubElement = false;
 605    }
 606   
 607  681 if ( handler == null )
 608    {
 609  0 if ( this.configurationStack.size( ) >= 1 )
 610    {
 611  0 endConfiguration( );
 612    }
 613  0 return;
 614    }
 615   
 616  681 this.current = getParent( handler.generateNodeFor( ) );
 617   
 618  681 Object node = handler.end( uri,
 619    localName );
 620   
 621    // next
 622  681 if ( node != null && !this.lastWasEndElement )
 623    {
 624  134 this.peer = node;
 625    }
 626    // up or no children
 627  547 else if ( this.lastWasEndElement || (this.parents.getLast( )).getClass( ).isInstance( this.current ) )
 628    {
 629  307 this.peer = this.parents.removeLast( );
 630    }
 631   
 632  681 this.lastWasEndElement = true;
 633    }
 634   
 635  683 private void validate(String uri,
 636    String localName,
 637    Handler handler) throws SAXParseException
 638    {
 639  683 boolean validParent = false;
 640  683 boolean validPeer = false;
 641  683 boolean invalidNesting = false;
 642   
 643  683 Set validParents = handler.getValidParents( );
 644  683 Set validPeers = handler.getValidPeers( );
 645  683 boolean allowNesting = handler.allowNesting( );
 646   
 647    // get parent
 648  683 Object parent;
 649  683 if ( this.parents.size( ) != 0 )
 650    {
 651  617 parent = this.parents.getLast( );
 652    }
 653    else
 654    {
 655  66 parent = null;
 656    }
 657   
 658    // check valid parents
 659    // null parent means localname is rule-set
 660    // dont process if elements are the same
 661    // instead check for allowed nesting
 662  683 Class nodeClass = getHandler( uri,
 663    localName ).generateNodeFor( );
 664  683 if ( !nodeClass.isInstance( parent ) )
 665    {
 666  683 Object allowedParent;
 667  683 Iterator it = validParents.iterator( );
 668  683 while ( !validParent && it.hasNext( ) )
 669    {
 670  683 allowedParent = it.next( );
 671  683 if ( parent == null && allowedParent == null )
 672    {
 673  66 validParent = true;
 674    }
 675  617 else if ( allowedParent != null && ((Class) allowedParent).isInstance( parent ) )
 676    {
 677  617 validParent = true;
 678    }
 679    }
 680  683 if ( !validParent )
 681    {
 682  0 throw new SAXParseException( "<" + localName + "> has an invalid parent element",
 683    getLocator( ) );
 684    }
 685    }
 686   
 687    // check valid peers
 688    // null peer means localname is rule-set
 689  683 Object peer = this.peer;
 690   
 691  683 Object allowedPeer;
 692  683 Iterator it = validPeers.iterator( );
 693  683 while ( !validPeer && it.hasNext( ) )
 694    {
 695  1231 allowedPeer = it.next( );
 696  1231 if ( peer == null && allowedPeer == null )
 697    {
 698  372 validPeer = true;
 699    }
 700  859 else if ( allowedPeer != null && ((Class) allowedPeer).isInstance( peer ) )
 701    {
 702  311 validPeer = true;
 703    }
 704    }
 705  683 if ( !validPeer )
 706    {
 707  0 throw new SAXParseException( "<" + localName + "> is after an invalid element",
 708    getLocator( ) );
 709    }
 710   
 711  683 if ( !allowNesting )
 712    {
 713  683 it = this.parents.iterator( );
 714  683 while ( !invalidNesting && it.hasNext( ) )
 715    {
 716  1289 if ( nodeClass.isInstance( it.next( ) ) )
 717    {
 718  0 invalidNesting = true;
 719    }
 720    }
 721    }
 722  683 if ( invalidNesting )
 723    {
 724  0 throw new SAXParseException( "<" + localName + "> may not be nested",
 725    getLocator( ) );
 726    }
 727   
 728    }
 729   
 730    /**
 731    * Start a configuration node.
 732    *
 733    * @param name
 734    * Tag name.
 735    * @param attrs
 736    * Tag attributes.
 737    */
 738  453 protected void startConfiguration(String name,
 739    Attributes attrs)
 740    {
 741  453 this.characters = new StringBuffer( );
 742   
 743  453 DefaultConfiguration config = new DefaultConfiguration( name );
 744   
 745  453 int numAttrs = attrs.getLength( );
 746   
 747  453 for ( int i = 0; i < numAttrs; ++i )
 748    {
 749  143 config.setAttribute( attrs.getLocalName( i ),
 750    attrs.getValue( i ) );
 751    }
 752   
 753  453 if ( this.configurationStack.isEmpty( ) )
 754    {
 755  453 this.configurationStack.addLast( config );
 756    }
 757    else
 758    {
 759  0 ((DefaultConfiguration) this.configurationStack.getLast( )).addChild( config );
 760  0 this.configurationStack.addLast( config );
 761    }
 762    }
 763   
 764    /**
 765    * @param chars
 766    * @param start
 767    * @param len
 768    * @see org.xml.sax.ContentHandler
 769    */
 770  1660 public void characters(char[] chars,
 771    int start,
 772    int len)
 773    {
 774  1660 if ( this.characters != null )
 775    {
 776  676 this.characters.append( chars,
 777    start,
 778    len );
 779    }
 780    }
 781   
 782    /**
 783    * End a configuration node.
 784    *
 785    * @return The configuration.
 786    */
 787  453 protected Configuration endConfiguration()
 788    {
 789  453 DefaultConfiguration config = (DefaultConfiguration) this.configurationStack.removeLast( );
 790  453 if ( this.characters != null )
 791    {
 792  453 config.setText( this.characters.toString( ) );
 793    }
 794   
 795  453 this.characters = null;
 796   
 797  453 return config;
 798    }
 799   
 800  453 SemanticModule lookupSemanticModule(String uri,
 801    String localName) throws SAXParseException
 802    {
 803  453 SemanticModule module;
 804  453 try
 805    {
 806  453 module = this.repo.lookupSemanticModule( uri );
 807    }
 808    catch ( NoSuchSemanticModuleException e )
 809    {
 810  0 throw new SAXParseException( "no semantic module for namespace '" + uri + "' (" + localName + ")",
 811    getLocator( ) );
 812    }
 813  453 return module;
 814    }
 815   
 816    /**
 817    * Returned Handler can be null. Calling method decides whether to throw an
 818    * exception or not.
 819    *
 820    * @param uri
 821    * @param localName
 822    * @return
 823    */
 824  2047 private Handler getHandler(String uri,
 825    String localName)
 826    {
 827  2047 String type = null;
 828  2047 if ( localName.equals( "rule-set" ) )
 829    {
 830  197 type = "RuleSet";
 831    }
 832  1850 else if ( localName.equals( "parameter" ) )
 833    {
 834  492 type = "Parameter";
 835    }
 836    else
 837    {
 838  1358 SemanticModule module;
 839  1358 try
 840    {
 841  1358 module = this.repo.lookupSemanticModule( uri );
 842  1358 type = module.getType( localName );
 843    }
 844    catch ( NoSuchSemanticModuleException e )
 845    {
 846    // swallow as we just return a null handler
 847    }
 848    }
 849   
 850  2047 Handler handler = (Handler) this.handlers.get( type );
 851   
 852  2047 return handler;
 853    }
 854   
 855  78 LinkedList getParents()
 856    {
 857  78 return this.parents;
 858    }
 859   
 860  1517 Object getParent(Class parent)
 861    {
 862  1517 ListIterator it = this.parents.listIterator( this.parents.size( ) );
 863  1517 Object node = null;
 864  1517 while ( it.hasPrevious( ) )
 865    {
 866  2353 node = it.previous( );
 867  1143 if ( parent.isInstance( node ) ) break;
 868    }
 869  1517 return node;
 870    }
 871   
 872  0 Object getPeer()
 873    {
 874  0 return this.peer;
 875    }
 876   
 877  164 Object getCurrent()
 878    {
 879  164 return this.current;
 880    }
 881   
 882  126 public InputSource resolveEntity(String publicId,
 883    String systemId)
 884    {
 885    // Schema files must end with xsd
 886  126 if ( !systemId.toLowerCase( ).endsWith( "xsd" ) )
 887    {
 888  0 return null;
 889    }
 890   
 891    // try the actual location given by systemId
 892  126 try
 893    {
 894  126 URL url = new URL( systemId );
 895  126 return new InputSource( url.openStream( ) );
 896    }
 897    catch ( Exception e )
 898    {
 899    }
 900   
 901    // Try and get the index for the filename, else return null
 902  126 String xsd;
 903  126 int index = systemId.lastIndexOf( "/" );
 904  126 if ( index == -1 )
 905    {
 906  0 index = systemId.lastIndexOf( "\\" );
 907    }
 908  126 if ( index != -1 )
 909    {
 910  126 xsd = systemId.substring( index + 1 );
 911    }
 912    else
 913    {
 914  0 xsd = systemId;
 915    }
 916   
 917  126 ClassLoader cl = Thread.currentThread( ).getContextClassLoader( );
 918   
 919  126 if ( cl == null )
 920    {
 921  0 cl = RuleSetReader.class.getClassLoader( );
 922    }
 923   
 924    // Try looking in META-INF
 925  126 try
 926    {
 927  126 return new InputSource( cl.getResourceAsStream( "META-INF/" + xsd ) );
 928    }
 929    catch ( Exception e )
 930    {
 931    }
 932   
 933    // Try looking in /META-INF
 934  0 try
 935    {
 936  0 return new InputSource( cl.getResourceAsStream( "/META-INF/" + xsd ) );
 937    }
 938    catch ( Exception e )
 939    {
 940    }
 941   
 942    // Try looking at root of classpath
 943  0 try
 944    {
 945  0 return new InputSource( cl.getResourceAsStream( "/" + xsd ) );
 946    }
 947    catch ( Exception e )
 948    {
 949    }
 950   
 951    // Try current working directory
 952  0 try
 953    {
 954  0 return new InputSource( new BufferedInputStream( new FileInputStream( xsd ) ) );
 955    }
 956    catch ( Exception e )
 957    {
 958    }
 959   
 960  0 cl = ClassLoader.getSystemClassLoader( );
 961   
 962    // Try looking in META-INF
 963  0 try
 964    {
 965  0 return new InputSource( cl.getResourceAsStream( "META-INF/" + xsd ) );
 966    }
 967    catch ( Exception e )
 968    {
 969    }
 970   
 971    // Try looking in /META-INF
 972  0 try
 973    {
 974  0 return new InputSource( cl.getResourceAsStream( "/META-INF/" + xsd ) );
 975    }
 976    catch ( Exception e )
 977    {
 978    }
 979   
 980    // Try looking at root of classpath
 981  0 try
 982    {
 983  0 return new InputSource( cl.getResourceAsStream( "/" + xsd ) );
 984    }
 985    catch ( Exception e )
 986    {
 987    }
 988   
 989    // Try current working directory
 990  0 try
 991    {
 992  0 return new InputSource( new BufferedInputStream( new FileInputStream( xsd ) ) );
 993    }
 994    catch ( Exception e )
 995    {
 996    }
 997  0 return null;
 998    }
 999   
 1000  2 private void print(SAXParseException x)
 1001    {
 1002  2 String msg = this.message.format( new Object[]{x.getSystemId( ), new Integer( x.getLineNumber( ) ), new Integer( x.getColumnNumber( ) ), x.getMessage( )} );
 1003  2 System.out.println( msg );
 1004    }
 1005   
 1006  0 public void warning(SAXParseException x)
 1007    {
 1008  0 print( x );
 1009    }
 1010   
 1011  2 public void error(SAXParseException x)
 1012    {
 1013  2 print( x );
 1014    }
 1015   
 1016  0 public void fatalError(SAXParseException x) throws SAXParseException
 1017    {
 1018  0 print( x );
 1019  0 throw x;
 1020    }
 1021   
 1022    }