FileDocCategorySizeDatePackage
AndroidGDataClient.javaAPI DocAndroid 1.5 API18442Wed May 06 22:41:56 BST 2009com.google.android.gdata.client

AndroidGDataClient

public class AndroidGDataClient extends Object implements com.google.wireless.gdata.client.GDataClient
Implementation of a GDataClient using GoogleHttpClient to make HTTP requests. Always issues GETs and POSTs, using the X-HTTP-Method-Override header when a PUT or DELETE is desired, to avoid issues with firewalls, etc., that do not allow methods other than GET or POST.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final boolean
LOCAL_LOGV
private static final String
X_HTTP_METHOD_OVERRIDE
private static final String
DEFAULT_USER_AGENT_APP_VERSION
private static final int
MAX_REDIRECTS
private final com.google.android.net.GoogleHttpClient
mHttpClient
private android.content.ContentResolver
mResolver
Constructors Summary
public AndroidGDataClient(android.content.ContentResolver resolver)

deprecated
Use AndroidGDAtaClient(Context) instead.

        mHttpClient = new GoogleHttpClient(resolver, DEFAULT_USER_AGENT_APP_VERSION,
                true /* gzip capable */);
        mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
        mResolver = resolver;
    
public AndroidGDataClient(android.content.Context context)
Creates a new AndroidGDataClient.

param
context The ContentResolver to get URL rewriting rules from through the Android proxy server, using null to indicate not using proxy. The context will also be used by GoogleHttpClient for configuration of SSL session persistence.

       this(context, DEFAULT_USER_AGENT_APP_VERSION);
    
public AndroidGDataClient(android.content.Context context, String appAndVersion)
Creates a new AndroidGDataClient.

param
context The ContentResolver to get URL rewriting rules from through the Android proxy server, using null to indicate not using proxy. The context will also be used by GoogleHttpClient for configuration of SSL session persistence.
param
appAndVersion The application name and version to be used as the basis of the User-Agent. e.g., Android-GData/1.5.0.

        mHttpClient = new GoogleHttpClient(context, appAndVersion,
                true /* gzip capable */);
        mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
        mResolver = context.getContentResolver();
    
Methods Summary
public voidclose()

        mHttpClient.close();
    
private java.io.InputStreamcreateAndExecuteMethod(com.google.android.gdata.client.AndroidGDataClient$HttpRequestCreator creator, java.lang.String uriString, java.lang.String authToken)


        HttpResponse response = null;
        int status = 500;
        int redirectsLeft = MAX_REDIRECTS;

        URI uri;
        try {
            uri = new URI(uriString);
        } catch (URISyntaxException use) {
            Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
            throw new IOException("Unable to parse " + uriString + " as URI: "
                    + use.getMessage());
        }

        // we follow redirects ourselves, since we want to follow redirects even on POSTs, which
        // the HTTP library does not do.  following redirects ourselves also allows us to log
        // the redirects using our own logging.
        while (redirectsLeft > 0) {

            HttpUriRequest request = creator.createRequest(uri);

            AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
            // only add the auth token if not null (to allow for GData feeds that do not require
            // authentication.)
            if (!TextUtils.isEmpty(authToken)) {
                request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
            }
            if (LOCAL_LOGV) {
                for (Header h : request.getAllHeaders()) {
                    Log.v(TAG, h.getName() + ": " + h.getValue());
                }
            }

            if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "Executing " + request.getRequestLine().toString());
            }

            response = null;

            try {
                response = mHttpClient.execute(request);
            } catch (IOException ioe) {
                Log.w(TAG, "Unable to execute HTTP request." + ioe);
                throw ioe;
            }

            StatusLine statusLine = response.getStatusLine();
            if (statusLine == null) {
                Log.w(TAG, "StatusLine is null.");
                throw new NullPointerException("StatusLine is null -- should not happen.");
            }

            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, response.getStatusLine().toString());
                for (Header h : response.getAllHeaders()) {
                    Log.d(TAG, h.getName() + ": " + h.getValue());
                }
            }
            status = statusLine.getStatusCode();

            HttpEntity entity = response.getEntity();

            if ((status >= 200) && (status < 300) && entity != null) {
                InputStream in = AndroidHttpClient.getUngzippedContent(entity);
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    in = logInputStreamContents(in);
                }
                return in;
            }

            // TODO: handle 301, 307?
            // TODO: let the http client handle the redirects, if we can be sure we'll never get a
            // redirect on POST.
            if (status == 302) {
                // consume the content, so the connection can be closed.
                entity.consumeContent();
                Header location = response.getFirstHeader("Location");
                if (location == null) {
                    if (Log.isLoggable(TAG, Log.DEBUG)) {
                        Log.d(TAG, "Redirect requested but no Location "
                                + "specified.");
                    }
                    break;
                }
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "Following redirect to " + location.getValue());
                }
                try {
                    uri = new URI(location.getValue());
                } catch (URISyntaxException use) {
                    if (Log.isLoggable(TAG, Log.DEBUG)) {
                        Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
                        throw new IOException("Unable to parse " + location.getValue()
                                + " as URI.");
                    }
                    break;
                }
                --redirectsLeft;
            } else {
                break;
            }
        }

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Received " + status + " status code.");
        }
        String errorMessage = null;
        HttpEntity entity = response.getEntity();
        try {
            if (response != null && entity != null) {
                InputStream in = AndroidHttpClient.getUngzippedContent(entity);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buf = new byte[8192];
                int bytesRead = -1;
                while ((bytesRead = in.read(buf)) != -1) {
                    baos.write(buf, 0, bytesRead);
                }
                // TODO: use appropriate encoding, picked up from Content-Type.
                errorMessage = new String(baos.toByteArray());
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, errorMessage);
                }
            }
        } finally {
            if (entity != null) {
                entity.consumeContent();
            }
        }
        String exceptionMessage = "Received " + status + " status code";
        if (errorMessage != null) {
            exceptionMessage += (": " + errorMessage);
        }
        throw new HttpException(exceptionMessage, status, null /* InputStream */);
    
private org.apache.http.HttpEntitycreateEntityForEntry(com.google.wireless.gdata.serializer.GDataSerializer entry, int format)

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            entry.serialize(baos, format);
        } catch (IOException ioe) {
            Log.e(TAG, "Unable to serialize entry.", ioe);
            throw ioe;
        } catch (ParseException pe) {
            Log.e(TAG, "Unable to serialize entry.", pe);
            throw new IOException("Unable to serialize entry: " + pe.getMessage());
        }

        byte[] entryBytes = baos.toByteArray();

        if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
            try {
                Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
            } catch (UnsupportedEncodingException uee) {
                // should not happen
                throw new IllegalStateException("UTF-8 should be supported!",
                        uee);
            }
        }

        AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
        entity.setContentType(entry.getContentType());
        return entity;
    
public java.io.InputStreamcreateEntry(java.lang.String feedUrl, java.lang.String authToken, com.google.wireless.gdata.serializer.GDataSerializer entry)


        HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
        InputStream in = createAndExecuteMethod(
                new PostRequestCreator(null /* override */, entity),
                feedUrl,
                authToken);
        if (in != null) {
            return in;
        }
        throw new IOException("Unable to create entry.");
    
public com.google.wireless.gdata.client.QueryParamscreateQueryParams()

        return new QueryParamsImpl();
    
public voiddeleteEntry(java.lang.String editUri, java.lang.String authToken)

        if (StringUtils.isEmpty(editUri)) {
            throw new IllegalArgumentException(
                    "you must specify an non-empty edit url");
        }
        InputStream in =
            createAndExecuteMethod(
                    new PostRequestCreator("DELETE", null /* entity */),
                    editUri,
                    authToken);
        if (in == null) {
            throw new IOException("Unable to delete entry.");
        }
        try {
            in.close();
        } catch (IOException ioe) {
            // ignore
        }
    
public java.lang.StringencodeUri(java.lang.String uri)

        String encodedUri;
        try {
            encodedUri = URLEncoder.encode(uri, "UTF-8");
        } catch (UnsupportedEncodingException uee) {
            // should not happen.
            Log.e("JakartaGDataClient",
                  "UTF-8 not supported -- should not happen.  "
                  + "Using default encoding.", uee);
            encodedUri = URLEncoder.encode(uri);
        }
        return encodedUri;
    
public java.io.InputStreamgetFeedAsStream(java.lang.String feedUrl, java.lang.String authToken)


        InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken);
        if (in != null) {
            return in;
        }
        throw new IOException("Unable to access feed.");
    
public java.io.InputStreamgetMediaEntryAsStream(java.lang.String mediaEntryUrl, java.lang.String authToken)


        InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken);

        if (in != null) {
            return in;
        }
        throw new IOException("Unable to access media entry.");
    
private java.io.InputStreamlogInputStreamContents(java.io.InputStream in)
Log the contents of the input stream. The original input stream is consumed, so the caller must use the BufferedInputStream that is returned.

param
in InputStream
return
replacement input stream for caller to use
throws
IOException

        if (in == null) {
            return in;
        }
        // bufferSize is the (arbitrary) maximum amount to log.
        // The original InputStream is wrapped in a
        // BufferedInputStream with a 16K buffer.  This lets
        // us read up to 16K, write it to the log, and then
        // reset the stream so the the original client can
        // then read the data.  The BufferedInputStream
        // provides the mark and reset support, even when
        // the original InputStream does not.
        final int bufferSize = 16384;
        BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
        bin.mark(bufferSize);
        int wanted = bufferSize;
        int totalReceived = 0;
        byte buf[] = new byte[wanted];
        while (wanted > 0) {
            int got = bin.read(buf, totalReceived, wanted);
            if (got <= 0) break; // EOF
            wanted -= got;
            totalReceived += got;
        }
        Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
        bin.reset();
        return bin;
    
public java.io.InputStreamupdateEntry(java.lang.String editUri, java.lang.String authToken, com.google.wireless.gdata.serializer.GDataSerializer entry)

        HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
        InputStream in = createAndExecuteMethod(
                new PostRequestCreator("PUT", entity),
                editUri,
                authToken);
        if (in != null) {
            return in;
        }
        throw new IOException("Unable to update entry.");
    
public java.io.InputStreamupdateMediaEntry(java.lang.String editUri, java.lang.String authToken, java.io.InputStream mediaEntryInputStream, java.lang.String contentType)

        InputStream in = createAndExecuteMethod(
                new MediaPutRequestCreator(mediaEntryInputStream, contentType),
                editUri,
                authToken);
        if (in != null) {
            return in;
        }
        throw new IOException("Unable to write media entry.");