You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by bu...@apache.org on 2003/03/03 21:51:27 UTC

DO NOT REPLY [Bug 17620] New: - SourceDataSource loses some text/xml attachment data

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17620>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17620

SourceDataSource loses some text/xml attachment data

           Summary: SourceDataSource loses some text/xml attachment data
           Product: Axis
           Version: 1.1RC1
          Platform: PC
        OS/Version: Windows NT/2K
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: Serialization/Deserialization
        AssignedTo: axis-dev@ws.apache.org
        ReportedBy: gary.gordon@softwareagusa.com


There are actually two observed problems.  First, 
org.apache.axis.attachments.SourceDataSource doesn't correctly get the input 
data from a StreamSource object if either the StreamSource was not built with 
the constructor taking an InputStream or has not explicity had its input stream 
set via setInputStream().  SourceDataSource is getting the data via 
StreamSource.getInputStream(), which according to the Xalan docs, only returns 
a non-null value if the object has been initialized via an input stream as 
explained above.  So if you initialize your StreamSource with, say, a 
java.io.File object or System ID string, 0 bytes of data are retrieved in 
SourceDataSource. Admittedly, the Xalan docs say the InputStream is the 
preferred method of intialization, becuase otherwise the character set encoding 
can be lost when the output is produced, but getting the data with the default 
UTF-8 encoding is probably better than totally failing to get the data.

The other problem is that the way SourceDataSource uses the input stream, it 
assumes an atomic, non-blocking read, which is not guaranteed for a socket or 
URL stream.  This is because available() only yields what is available without 
blocking, and for sockets, a single read may not consume all the input.

I came up with a fix that addresses the first issue, modulo the concern about 
encodings, and can improve the partial read issue somewhat, but I am not sure 
it makes sense to suddenly add blocking read semantics.  Here is the existing 
logic:

InputStream is = data.getInputStream();
if (is != null && is.available() > 0) {
  byte[] bytes = new byte[is.available()];
  is.read(bytes);
  os.write(bytes);
}

A proposed solution which fixes the atomic read problem, but not non-blocking, 
and creates UTF-8 encoded data when the InputStream is not available is:

import javax.xml.transform.*;
...
InputStream is = data.getInputStream();
if (is != null) {
  // If reading from a socket or URL, we could get a partial read.
  byte[] bytes = null;
  int avail;
  while ((avail = is.available()) > 0) {
    if (bytes == null || avail > bytes.length)
      bytes = new byte[avail];
    is.read(bytes, 0, avail);
    os.write(bytes, 0, avail);
  }
} else {
  // Create a transformer with no stylesheet (no transformation).
  StreamResult res = new StreamResult(os);
  TransformerFactory tf = TransformerFactory.newInstance();
  Transformer serializer = tf.newTransformer();
  serializer.transform(data, res);
}

Here is a test program showing how the available bytes are 0 when the 
StreamSource is built from a URL string.

import javax.xml.transform.stream.StreamSource;
import org.apache.axis.attachments.SourceDataSource;
public class stst {
  public static void main(String[] args) throws Exception {
    // Case 1: breaks because calling getInputStream()
    // from StreamSource returned null.
    StreamSource ssrc = new StreamSource
      "http://www.xmethods.net/sd/2001/BNQuoteService.wsdl");
    SourceDataSource sds = new SourceDataSource("foo", "text/xml", ssrc);
    System.out.println("case 1 available bytes: " +
      sds.getInputStream().available());
		
    // Case 2: works ONLY because StreamSource was invoked with InputStream
    // constructor.  May still fail if socket read isn't atomic.
    java.net.URL url = new java.net.URL(
      "http://www.xmethods.net/sd/2001/BNQuoteService.wsdl");
    ssrc = new StreamSource(url.openStream(), "http://foo.com");
    sds = new SourceDataSource("foo", "text/xml", ssrc);
    System.out.println("case 2 available bytes: " +
      sds.getInputStream().available());
  }
}

My java version is:
java full version "1.4.1-b21"

Gary