#228 error handling in contrib/pure-scheme/sexp-xml.scm

open
nobody
None
5
2007-07-09
2007-07-09
Anonymous
No

sisc 1.16.6

the bug occurs for example if org.sax can't find the DTD (see below) or if java runs out of memory because of a very large XML-file (47MB, deeply nested and with references to external XML-Entities).

sisc@fahrrad> (sexp-xml:xml->sexp/file "foo.xml")
Error in ->string: <java.lang.NullPointerException>: null
---------------------------
file:/home/johannes/sisc/contrib/pure-scheme/sexp-xml.scm:293:31: <from call to @s2j-conversion::->string>
---------------------------
file:/home/johannes/sisc/contrib/pure-scheme/sexp-xml.scm:266:5: <from call to with/fc>
---------------------------
file:/home/johannes/sisc/contrib/pure-scheme/sexp-xml.scm:234:3: <indeterminate call>
console:314:1: <from call to @sexp-xml::sexp-xml:xml->sexp/file>

i defined all functions from sexp-xml.scm inside the repl and tested only what goes into arg1 of with/fc (lambda (m e) ...) inside function sexp->xml/input-source: i tried to construct (parse xml-reader input-source) manually and received the following error (which lead to the above error when calling from outside):

sisc@fahrrad> (let* ((input-source (java-new <org.xml.sax.input-source> (java-new <java.io.file-reader> (|->jstring| "/home/johannes/du/cvs-modules/traffic-nrw-dav/doc/versorgungsdatei.OLSIM.sample.xml")))) (sa (new-ssax-accumulator)) (xml-reader (get-xml-reader-with-proxy (make-content-handler-proxy sa)))) (parse xml-reader input-source))
Error: #<java java.io.FileNotFoundException java.io.FileNotFoundException: /usr/home/johannes/K2S.dtd (No such file or directory)>
java.io.FileNotFoundException: /usr/home/johannes/K2S.dtd (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70)
at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:973)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:905)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:872)
at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:282)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(XMLDocumentScannerImpl.java:1021)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:368)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:834)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1242)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at sisc.modules.s2j.Operation.invokeMethod(Unknown Source)
at sisc.modules.s2j.Operation.doApply(Unknown Source)
at sisc.nativefun.NativeProcedure.apply(Unknown Source)
at sisc.exprs.AppEval.eval(Unknown Source)
at sisc.interpreter.Interpreter.next(Unknown Source)
at sisc.exprs.AppExp.eval(Unknown Source)
at sisc.interpreter.Interpreter.interpret(Unknown Source)
at sisc.interpreter.Interpreter.interpret(Unknown Source)
at sisc.interpreter.Interpreter.eval(Unknown Source)
at sisc.data.SchemeThread.run(Unknown Source)
at java.lang.Thread.run(Thread.java:595)
---------------------------
console:266:296: <from call to parse>

Discussion

  • from my independent findings -

    1) if its something as basic as the actual xml file passed in doesn't exist, the libraries behavior is sufficient. (to be friendly, it could put a pretty wrapper to hide the internal java exception.). overall, i would write client code as follows:

    (with/fc
    (lambda (m e)

     
  • [continuing, hit submit by mistake..]

    (with/fc
    (lambda (er ek)
    (define-java-classes <java.io.file-not-found-exception>)
    (let* ((e (error-message er)))
    (if (instance-of? e <java.io.file-not-found-exception>)
    ...handle exception...
    (throw er))))
    (lambda ()
    (sexp->xml:xml->sexp/file "missing.xml")
    )))

    2) but if you hit an error that is not a "sax exception", you do actually hit a bug in the exception wrapping. in that case, the library implementation of xml->sexp/input-source should be changed. currently, if you pass in a xml file that references a missing dtd file, the exception wrapping code crashes when trying to invoke "get-cause" on the exception. in order to allow the true exception to bubble up instead of the null pointer exception caused by trying to run incompatible procedure get-cause on the error-record, i would change the else part of the if clause in the exception handler inside xml->sexp/input-source to something like:

    (throw (make-nested-error (make-error 'xml->sexp/input-source "parse error") m e)

    then the client of the library will get complete errors for missing dtd's and other non-sax exceptions like "

    Error in xml->sexp/input-source: parse error
    Caused by Error: #<java java.io.FileNotFoundException java.io.FileNotFoundException: /tmp/note.dtd (No such file or directory)>
    java.io.FileNotFoundException: /tmp/note.dtd (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    ...
    " which can be handled specifically using type tests on the error-message of the error-record as demonstrated above.

    I did not test this fix on an xml file too large for parsing. worse case, use with/fc and a catch all exception handler

    -kanishka