When creating a new entry with Service.insert() method,
the current implementation seems to expect a non-empty response stream.
If the stream is empty, it throws a SAX ParseException of "Premature
end of file".

Technically, this happens because the Entry.parseAtom() method is
called and the BaseEntry superclass implementation does not test for
the presence of actual content on this stream before trying to parse
it.  Another way to look at it is that the HttpGDataRequest
implementation always assumes an 'insert' will result in a non-empty
response and thus returns the connection's input stream even if it is
empty.

The ATOM publishing spec

http://www.ietf.org/internet-drafts/draft-ietf-atompub-protocol-09.txt

has the following in section 5.2 (Creating a resource) :

2.  If the Member resource was created successfully, the server
       responds with a status code of 201 and a Location: header that
       contains the URI of the newly created resource.

and later, in section 8.1

   When the server generates a response with a status code of 201
   ("Created"), it SHOULD also return a response body, which, if
   provided, MUST be an Atom Entry Document representing the newly-
   created resource.  Clients MUST NOT assume that an Atom Entry
   returned is a full representation of the member resource.

The observed behavior of the GData Service, GDataRequest and BaseEntry
implemetations a) throw a ParseException if no response body is sent
back, b) ignore the Location header and c) do not provide the developer
easy access to the Location header.

Thus, the GData Service, GDataRequest and BaseEntry implementation
classes 'out of the box'  are not quite in spirit with the above spec
and cannot be used with all ATOM
feeds out there without some work-arounds applied.

To work-around this, you need to create subclasses of
GoogleGDataRequest and
GoogleGDataRequest.Factory.

In your subclass of GoogleGDataRequest, overload the constructor to
save the authToken and userAgent parameters in instance fields (in
addition to passing them on to the super(...) constructor, of course).

Then, overload the getResponse method like so:
  1) get the input stream from super.getResponseStream()
  2)  test the stream to see if it has data
  2a) if it has data, reset it and return it.
  2b) if it doesn't, use the protected httpConn field to get access to
the "Location"
         response header:     String loc =
httpConn.getHeaderField("Location");
  2b0) if the Location header is not there, then you are screwed
because the service
         is not compliant with the atom spec.  You could put in a dummy
stream here
         based on a bytearrayinputstream to avoid the GData bug, if you
want. 'Better to
         throw an exception noting the out-of-compliance feed.
  2b1) if the Location header is there, use the specified URL to open a
stream to the
          posted entry.  Be sure to use the authToken and userAgent
data you saved
          up above to set the headers for the new connection.  Return
this stream.

In your subclass of GooglGDataRequest.Factory, simply override the
getRequest() method so it creates your request subclass.

Finally, just remember to use the GoogleService.setRequestFactory()
method to set your factory before using the service.

It would be really nice if the steps 2->2b1 above were added to the
base HttpGDataRequest.getResponseStream() method.  This would bring the
GData API client libraries into compliance with the Atom spec.

Here is a snippet of a replacement GDataRequest implementation as
described above:

public static class MyGDataRequest extends GoogleGDataRequest {

        public static class Factory extends GoogleGDataRequest.Factory {
                public GDataRequest getRequest(RequestType type, URL requestUrl,
                                ContentType contentType) throws IOException,
                                ServiceException {
                        return new MyGDataRequest(type, requestUrl, contentType,
                                        authToken, userAgent);
                }

        }

        private AuthToken authToken = null;
        private String userAgent = null;

        protected MyGDataRequest(RequestType type, URL requestUrl,
                        ContentType contentType, AuthToken authToken, String 
userAgent)
                        throws IOException {
                super(type, requestUrl, contentType, authToken, userAgent);
                this.authToken = authToken;
                this.userAgent = userAgent;
        }

        public InputStream getResponseStream() throws IOException {
          InputStream input = super.getResponseStream();
          if(input!=null){
                  //test for non-empty stream
                  InputStream bis = new BufferedInputStream(input);
                  bis.mark(16);
                  int test = bis.read();
                  if(test<0){
                          input=null;//empty stream
                  }else{
                          bis.reset();
                          input = bis;
                  }
          }
          if(input==null){
                  String location = httpConn.getHeaderField("Location");
                  if(location!=null){
                          URL loc = new URL(location);
                          HttpURLConnection locConn =
                                (HttpURLConnection)loc.openConnection();
                          String authProperty =
                                httpConn.getRequestProperty("Authorization");
                          if(authToken!=null){
                                  locConn.setRequestProperty("Authorization",
                                        
authToken.getAuthorizationHeader(loc.toExternalForm()));
                          }
                          if (userAgent != null) {
                                  locConn.setRequestProperty("User-Agent", 
userAgent);
                          }
                          input = locConn.getInputStream();
                  }
          }
          return input;
        }
}


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Google Calendar Data API" group.
To post to this group, send email to 
[email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/google-calendar-help-dataapi
-~----------~----~----~----~------~----~------~--~---

Reply via email to