[ 
http://issues.apache.org/jira/browse/AXIS2-919?page=comments#action_12429158 ] 
            
Derek Foster commented on AXIS2-919:
------------------------------------

Hi, Chinthaka.

Thanks for the reply. I think I understand what you are suggesting about what 
the bug is. I'm not sure I complely agree with you about the full solution, 
however.

I think that your point that the exception cannot be legitimately thrown when 
invoked from reading a correctly well-formed XML document is probably correct, 
and that your point that this indicates an error in XMLBeans binding code is 
also probably correct. This is probably the "real" error that is triggering the 
failure that I see.

However, I still think that there is a problem in AXIOM which also is being 
manifested here. 

According to the Sun documentation for the java.util.Iterator interface, the 
following loop:

    while (iterator.hasNext())
         iterator.next();

should not throw any exceptions at all, ever, unless there is a bug in the 
program. (Note that simply receiving half of an XML document from an external 
source does not constitute a bug in the program.) 

If next() is called when hasNext() returns true, it should always return a 
result. If it is called when hasNext() is not true, it should throw 
NoSuchElementException. This is all as per the JavaDocs for java.util.Iterator. 
The accepted way for an Iterator to indicate that it has reached the end of its 
input sequence is for its hasNext() method to return false, not for either it 
or next() to throw an exception.

The java.util.Iterator interface provides no way to detect "erroneous" versus 
"normal" end of input conditions, and as such, it may not be an appropriate 
class to use for this particular application. If you want to detect errors when 
traversing the data, perhaps there should be an OMIterator interface used 
instead, or even better (see below) an OMCollection, which could legitimately 
throw exceptions if necessary. However, the standard java.util.Iterator is 
defined not to do this, ever, and so code that implements it in a way that 
throws exceptions is actually violating this interface's documented contract 
with its clients. (Note that the clients may not be aware that the Iterator 
that they have been handed is actually an Iterator from OMElement and not from 
some other source, so they may be quite unprepared to handle exceptions of this 
sort.)

Now, if you can guarantee that all implementations of the interface will never 
really throw any exceptions except under "internal implementation error" 
conditions (which is what unchecked exceptions like RuntimeExceptions are for), 
that's fine, but it seems to me that this would require some sort of mandatory 
preparsing and error reporting pass on the XML (at construction time of the 
OMElement?) prior to iterating over it "for real". In general,  when reading 
XML that has not been parsed before, it seems to me that a "premature end of 
input" condition is pretty much always possible, and that code should therefore 
not be throwing a runtime exception if it occurs.

Anyway, in the current implementation, it appears to me that the hasNext() 
method is incorrectly indicating "yes, there is a next element" when in fact 
there isn't one, so next() throws an exception when called. It seems to me that 
if this error is going to be detected at all, that it should be detected by 
hasNext(), not by next(), and the manner of reporting this error should simply 
be that hasNext() returns false. If unbalanced start...end pairs exist in the 
XML document, it seems to me that it the caller of hasNext()...next()'s job to 
detect that, not the responsibility of the Iterator instance itself.

Derek


> Unable to print out entire SOAP message: bug in OMElement.serialize()
> ---------------------------------------------------------------------
>
>                 Key: AXIS2-919
>                 URL: http://issues.apache.org/jira/browse/AXIS2-919
>             Project: Apache Axis 2.0 (Axis2)
>          Issue Type: Bug
>          Components: core, om
>    Affects Versions: 1.0
>            Reporter: Derek Foster
>         Assigned To: Eran Chinthaka
>            Priority: Blocker
>
> I was attempting, inside an XMLBeans-generated service method, to print out 
> the entire SOAP message to a log file. Towards that end, I tried to execute 
> the following code:
> final StringWriter writer = new StringWriter();
> messageContext.getEnvelope().serialize(writer);
> System.out.println(writer.toString());
> However, I was surprised to get the following exception resulting from this:
> org.apache.axiom.om.OMException
>       at 
> org.apache.axiom.om.impl.llom.OMElementImpl.getNextOMSibling(OMElementImpl.java:266)
>       at 
> org.apache.axiom.om.impl.traverse.OMChildrenIterator.next(OMChildrenIterator.java:111)
>       at 
> org.apache.axiom.om.impl.llom.OMElementImpl.internalSerialize(OMElementImpl.java:771)
>       at 
> org.apache.axiom.soap.impl.llom.SOAPEnvelopeImpl.internalSerialize(SOAPEnvelopeImpl.java:177)
>       at 
> org.apache.axiom.om.impl.llom.OMElementImpl.internalSerialize(OMElementImpl.java:756)
>       at 
> org.apache.axiom.om.impl.llom.OMNodeImpl.serialize(OMNodeImpl.java:310)
>       at 
> org.apache.axiom.om.impl.llom.OMNodeImpl.serialize(OMNodeImpl.java:352)
>        ...
> The cause of the problem appears to be the fact that the SOAP envelope is a 
> top-level XML object. Thus, the item immediately following it is a 
> DOCUMENT_END. The OMElementImpl.internalSerialize(XMLStreamWriter, boolean 
> cache) method contains the following code:
>             Iterator children = this.getChildren();
>             while (children.hasNext()) {
>                 ((OMNodeEx) children.next()).internalSerialize(writer);
> which seems plausible. However, the iterator that is returned is of type 
> OMChildrenIterator. Its hasNext method looks like this:
>     /**
>      * Returns <tt>true</tt> if the iteration has more elements. (In other
>      * words, returns <tt>true</tt> if <tt>next</tt> would return an element
>      * rather than throwing an exception.)
>      *
>      * @return Returns <tt>true</tt> if the iterator has more elements.
>      */
>     public boolean hasNext() {
>         return (currentChild != null);
>     }
> but its next() method looks like this:
>     /**
>      * Returns the next element in the iteration.
>      *
>      * @return Returns the next element in the iteration.
>      * @throws java.util.NoSuchElementException
>      *          iteration has no more elements.
>      */
>     public Object next() {
>         nextCalled = true;
>         removeCalled = false;
>         if (hasNext()) {
>             lastChild = currentChild;
>             currentChild = currentChild.getNextOMSibling();
>             return lastChild;
>         }
>         return null;
>     }
> which is a problem, because currentChild.getNextOMSibling() looks like this:
>     /**
>      * Gets the next sibling. This can be an OMAttribute or OMText or
>      * OMELement for others.
>      *
>      * @throws OMException
>      */
>     public OMNode getNextOMSibling() throws OMException {
>         while (!done) {
>             int token = builder.next();
>             if (token == XMLStreamConstants.END_DOCUMENT) {
>                 throw new OMException();
>             }
>         }
>         return super.getNextOMSibling();
>     }
> which will under some circumstances throw an OMException, which is not in the 
> contract of the iterator's next() method to throw.
> Thus, iterator.hasNext() is returning true, implying that there is a next 
> element, but when next() is actually called, the iterator discovers that it 
> has reached the end of the document, and that therefore there really is no 
> next element. It therefore throws an OMException.
> Firstly, if the next() method is going to be implemented this way, then 
> hasNext() should perform enough lookahead on the document to detect that the 
> next item in the input stream is indeed a END_DOCUMENT, and should therefore 
> return false, since under these circumstances there truly isn't a next 
> element (and calling next() would therefore always throw an OMException). 
> That way, when the end of the document is hit, the serialize method will 
> simply stop and return its results rather than trying to advance past the end 
> of the document as it does now.
> Secondly, this OMException really should have some meaningful error text in 
> it, such as "Can't call 'next()' on an iterator which is positioned at 
> element 'foo' which is the last element in the document" or even better, 
> "Can't call next() when hasNext() returns false" (see below). I can't think 
> of any cases in typical library code where it is desirable to throw 
> exceptions that don't have any message text. This is really unpleasant for 
> anybody that is trying to debug a problem. I would encourage someone to do a 
> search through the source code for "throw new OMException()" and add an 
> explanatory error message wherever one is found.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to