Parser2 considered harmful

Miles Sabin msabin at cromwellmedia.co.uk
Tue May 18 16:54:49 BST 1999


David Megginson wrote,
> Miles Sabin writes:
> > It's not diamond inheritance per-se which is the
> > problem, it's (as you point out) the potential for a
> > combinatorial explosion of derived interfaces which is
> > nasty.
>
> Some concrete examples might be helpful -- I know that 
> the get/setFeature/Property methods in Parser2 are not a 
> silver bullet, but under what circumstances might people 
> want to subclass Parser2 further in the future?

Err ... no, that's not what I meant. getProperty() deals
with things quite nicely. It's an example of something 
Erich Gamma calls the 'Extension Objects Pattern'. See,

  http://www.cs.wustl.edu/~schmidt/PLoP-96/gamma.txt

(only an abstract I'm afraid).

My point was more along the lines of getProperty() etc.
are (or, at least, will be) core Parser functionality,
and that they should, if possible, be defined in the main 
Parser interface, rather than relegated to an auxilliary
extension interface. The various discussions on the DOM
IG seem to have come to the conclusion that augmenting
interfaces in this way isn't problematic in Java, and
that it's the cleanest and most comprehensible solution
to the interface evolution problem.

The biggest problem with the Parser2 route is that it 
interacts badly with ParserFactory. ParserFactory's
methods return Parsers, so if getProperty() is defined
on Parser2 I have to cast before I can call it, and that's 
ugly, particularly since the cast might fail. 
ParserFactory can't be modified so that it's methods 
return Parser2s without breaking signature compatability 
with SAX1, but we can add the new methods directly to 
Parser without causing any problems.

Actually, this probably needs a bit of clarification. I
guess a rejoinder might be: doesn't this break
compatibility with parsers which only implement the
current Parser interface? Ie. with a current parser,
wouldn't the effect of,

  Parser p = ParserFactory.makeParser();
  p.setProperty
    ("http://xml.org/sax/properties/dtd-handler",
     myDTDHandler);

be to throw a NoSuchMethodException?

In fact this doesn't need to happen, because the SAX2
ParserFactory could do something like this,

  public static Parser makeParser()
  {
    Parser p;

    // Original stuff elided
    
    try
    {
      p.getProperty("dummy");
      
      // we get here if we're SAX2 compatible ...
      return p;
    }
    catch(NoSuchMethodException ex)
    {
      // ... we get here if we're not.
      return new SAX1ParserAdapter(p);
    }
  }

Where SAX1ParserAdapter is defined as follows,

  class SAX1ParserAdapter
    implements Parser
  {
    private Parser itsBaseParser;
    private DocumentHandler itsDocumentHandler = null;
    private DTDHandler itsDTDHandler = null;
    private EntityResolver itsEntityResolver = null;
    private ErrorHandler itsErrorHandler = null;
    private Locale itsLocale = null;

    public SAX1ParserAdapter(Parser baseParser)
    {
      itsBaseParser = baseParser;
    }

    public void setDocumentHandler
      (DocumentHandler handler)
    {
      // cache locally ...
      itsDocumentHandler = handler;

      // forward to underlying SAX1 parser ...
      itsBaseParser.setDocumentHandler(handler);
    }

    // etc. for for other Parser methods that can be
    // safely forwarded to a SAX1 parser.

    public void setFeature
      (String featureId, boolean state)
    {
      // throw relevant exceptions
    }

    public boolean getFeature(String featureId) 
    {
      // return SAX1 compatible results or throw
      // relevant exceptions
    }

    public void setProperty
      (String propertyId, Object value) 
    {
      // call SAX1 Parser.setXXXHandler() methods
      // where appropriate (and cache locally), or
      // throw relevant exceptions.
    }

    public Object getProperty(String propertyId)
    {
      // return locally cached handlers where
      // appropriate, or throw relevant exceptions.
    }
  }

This should work with all possible combinations of
SAX parsers, and SAX client applications.

Case 1: SAX1 parser, SAX1 client
  No problem, it's the current situation.

Case 2: SAX1 parser, SAX2 client
  No problem, dealt with by adapter as above. SAX2 client
  can use SAX2 methods without casting and without having
  to worry about NoSuchMethodExceptions.

Case 3: SAX2 parser, SAX1 client
  No problem, SAX2 interfaces are backwards compatible.

Case 4: SAX2 parser, SAX2 client.
  No problem. As in case 2, the SAX2 client can use SAX2 
  methods without casting and without having to worry 
  about NoSuchMethodExceptions.

Note that this assumes that a SAX2 client can only be
built against SAX2 interfaces and classes (which is fine
because that's guaranteed), and that a SAX2 client will
be able to ensure that the SAX2 ParserFactory is on its
classpath at runtime (which shouldn't be a problem).

Cheers,


Miles

-- 
Miles Sabin                          Cromwell Media
Internet Systems Architect           5/6 Glenthorne Mews
+44 (0)181 410 2230                  London, W6 0LJ
msabin at cromwellmedia.co.uk           England

xml-dev: A list for W3C XML Developers. To post, mailto:xml-dev at ic.ac.uk
Archived as: http://www.lists.ic.ac.uk/hypermail/xml-dev/ and on CD-ROM/ISBN 981-02-3594-1
To (un)subscribe, mailto:majordomo at ic.ac.uk the following message;
(un)subscribe xml-dev
To subscribe to the digests, mailto:majordomo at ic.ac.uk the following message;
subscribe xml-dev-digest
List coordinator, Henry Rzepa (mailto:rzepa at ic.ac.uk)




More information about the Xml-dev mailing list