diff options
Diffstat (limited to 'core')
7 files changed, 1 insertions, 1429 deletions
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index b8cf6c2..1652ebd 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -33,17 +33,6 @@ import android.text.format.Time; import android.util.Config; import android.util.Log; import android.accounts.Account; -import com.android.internal.database.ArrayListCursor; -import com.google.android.gdata.client.AndroidGDataClient; -import com.google.android.gdata.client.AndroidXmlParserFactory; -import com.google.wireless.gdata.calendar.client.CalendarClient; -import com.google.wireless.gdata.calendar.data.EventEntry; -import com.google.wireless.gdata.calendar.data.Who; -import com.google.wireless.gdata.calendar.parser.xml.XmlCalendarGDataParserFactory; -import com.google.wireless.gdata.data.StringUtils; - -import java.util.ArrayList; -import java.util.Vector; /** * The Calendar provider contains all calendar events. @@ -547,8 +536,6 @@ public final class Calendar { AttendeesColumns.ATTENDEE_TYPE, AttendeesColumns.ATTENDEE_STATUS }; - private static CalendarClient sCalendarClient = null; - public static final Cursor query(ContentResolver cr, String[] projection) { return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER); } @@ -600,7 +587,7 @@ public final class Calendar { // where String where = extractValue(event, "LOCATION"); - if (!StringUtils.isEmpty(where)) { + if (!TextUtils.isEmpty(where)) { values.put(EVENT_LOCATION, where); } @@ -687,47 +674,6 @@ public final class Calendar { } /** - * Returns a singleton instance of the CalendarClient used to fetch entries from the - * calendar server. - * @param cr The ContentResolver used to lookup the address of the calendar server in the - * settings database. - * @return The singleton instance of the CalendarClient used to fetch entries from the - * calendar server. - */ - private static synchronized CalendarClient getCalendarClient(ContentResolver cr) { - if (sCalendarClient == null) { - sCalendarClient = new CalendarClient( - new AndroidGDataClient(cr), - new XmlCalendarGDataParserFactory(new AndroidXmlParserFactory())); - } - return sCalendarClient; - } - - /** - * Extracts the attendees information out of event and adds it to a new ArrayList of columns - * within the supplied ArrayList of rows. These rows are expected to be used within an - * {@link ArrayListCursor}. - */ - private static final void extractAttendeesIntoArrayList(EventEntry event, - ArrayList<ArrayList> rows) { - Log.d(TAG, "EVENT: " + event.toString()); - Vector<Who> attendees = (Vector<Who>) event.getAttendees(); - - int numAttendees = attendees == null ? 0 : attendees.size(); - - for (int i = 0; i < numAttendees; ++i) { - Who attendee = attendees.elementAt(i); - ArrayList row = new ArrayList(); - row.add(attendee.getValue()); - row.add(attendee.getEmail()); - row.add(attendee.getRelationship()); - row.add(attendee.getType()); - row.add(attendee.getStatus()); - rows.add(row); - } - } - - /** * The content:// style URL for this table */ public static final Uri CONTENT_URI = diff --git a/core/java/com/google/android/gdata/client/AndroidGDataClient.java b/core/java/com/google/android/gdata/client/AndroidGDataClient.java deleted file mode 100644 index 9a2a51d..0000000 --- a/core/java/com/google/android/gdata/client/AndroidGDataClient.java +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2007 The Android Open Source Project - -package com.google.android.gdata.client; - -import com.google.android.net.GoogleHttpClient; -import com.google.wireless.gdata.client.GDataClient; -import com.google.wireless.gdata.client.HttpException; -import com.google.wireless.gdata.client.QueryParams; -import com.google.wireless.gdata.data.StringUtils; -import com.google.wireless.gdata.parser.ParseException; -import com.google.wireless.gdata.serializer.GDataSerializer; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.entity.ByteArrayEntity; - -import android.content.ContentResolver; -import android.content.Context; -import android.net.http.AndroidHttpClient; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; -import android.os.SystemProperties; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.io.BufferedInputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; - -/** - * 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. - */ -public class AndroidGDataClient implements GDataClient { - - private static final String TAG = "GDataClient"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; - - private static final String X_HTTP_METHOD_OVERRIDE = - "X-HTTP-Method-Override"; - - private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.1"; - - private static final int MAX_REDIRECTS = 10; - - // boolean system property that can be used to control whether or not - // requests/responses are gzip'd. - private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip"; - - private final GoogleHttpClient mHttpClient; - private ContentResolver mResolver; - - /** - * Interface for creating HTTP requests. Used by - * {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for - * changing the URI after creation, e.g., when you want to follow a redirect. - */ - private interface HttpRequestCreator { - HttpUriRequest createRequest(URI uri); - } - - private static class GetRequestCreator implements HttpRequestCreator { - public GetRequestCreator() { - } - - public HttpUriRequest createRequest(URI uri) { - HttpGet get = new HttpGet(uri); - return get; - } - } - - private static class PostRequestCreator implements HttpRequestCreator { - private final String mMethodOverride; - private final HttpEntity mEntity; - public PostRequestCreator(String methodOverride, HttpEntity entity) { - mMethodOverride = methodOverride; - mEntity = entity; - } - - public HttpUriRequest createRequest(URI uri) { - HttpPost post = new HttpPost(uri); - if (mMethodOverride != null) { - post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride); - } - post.setEntity(mEntity); - return post; - } - } - - // MAJOR TODO: make this work across redirects (if we can reset the InputStream). - // OR, read the bits into a local buffer (yuck, the media could be large). - private static class MediaPutRequestCreator implements HttpRequestCreator { - private final InputStream mMediaInputStream; - private final String mContentType; - public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) { - mMediaInputStream = mediaInputStream; - mContentType = contentType; - } - - public HttpUriRequest createRequest(URI uri) { - HttpPost post = new HttpPost(uri); - post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT"); - // mMediaInputStream.reset(); - InputStreamEntity entity = new InputStreamEntity(mMediaInputStream, - -1 /* read until EOF */); - entity.setContentType(mContentType); - post.setEntity(entity); - return post; - } - } - - /** - * @deprecated Use AndroidGDAtaClient(Context) instead. - */ - public AndroidGDataClient(ContentResolver resolver) { - mHttpClient = new GoogleHttpClient(resolver, DEFAULT_USER_AGENT_APP_VERSION, - true /* gzip capable */); - mHttpClient.enableCurlLogging(TAG, Log.VERBOSE); - mResolver = resolver; - } - - /** - * 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. - */ - public AndroidGDataClient(Context context) { - this(context, DEFAULT_USER_AGENT_APP_VERSION); - } - - /** - * 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. - */ - public AndroidGDataClient(Context context, String appAndVersion) { - mHttpClient = new GoogleHttpClient(context, appAndVersion, - true /* gzip capable */); - mHttpClient.enableCurlLogging(TAG, Log.VERBOSE); - mResolver = context.getContentResolver(); - } - - public void close() { - mHttpClient.close(); - } - - /* - * (non-Javadoc) - * @see GDataClient#encodeUri(java.lang.String) - */ - public String encodeUri(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; - } - - /* - * (non-Javadoc) - * @see com.google.wireless.gdata.client.GDataClient#createQueryParams() - */ - public QueryParams createQueryParams() { - return new QueryParamsImpl(); - } - - // follows redirects - private InputStream createAndExecuteMethod(HttpRequestCreator creator, - String uriString, - String authToken) - throws HttpException, IOException { - - 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); - - if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) { - 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 */); - } - - /* - * (non-Javadoc) - * @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String) - */ - public InputStream getFeedAsStream(String feedUrl, - String authToken) - throws HttpException, IOException { - - InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken); - if (in != null) { - return in; - } - throw new IOException("Unable to access feed."); - } - - /** - * 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 - */ - private InputStream logInputStreamContents(InputStream in) 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 InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken) - throws HttpException, IOException { - - InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken); - - if (in != null) { - return in; - } - throw new IOException("Unable to access media entry."); - } - - /* (non-Javadoc) - * @see GDataClient#createEntry - */ - public InputStream createEntry(String feedUrl, - String authToken, - GDataSerializer entry) - throws HttpException, IOException { - - 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."); - } - - /* (non-Javadoc) - * @see GDataClient#updateEntry - */ - public InputStream updateEntry(String editUri, - String authToken, - GDataSerializer entry) - throws HttpException, IOException { - 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."); - } - - /* (non-Javadoc) - * @see GDataClient#deleteEntry - */ - public void deleteEntry(String editUri, String authToken) - throws HttpException, IOException { - 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 InputStream updateMediaEntry(String editUri, String authToken, - InputStream mediaEntryInputStream, String contentType) - throws HttpException, IOException { - InputStream in = createAndExecuteMethod( - new MediaPutRequestCreator(mediaEntryInputStream, contentType), - editUri, - authToken); - if (in != null) { - return in; - } - throw new IOException("Unable to write media entry."); - } - - private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException { - 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; - if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) { - entity = new ByteArrayEntity(entryBytes); - } else { - entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver); - } - entity.setContentType(entry.getContentType()); - return entity; - } -} diff --git a/core/java/com/google/android/gdata/client/AndroidXmlParserFactory.java b/core/java/com/google/android/gdata/client/AndroidXmlParserFactory.java deleted file mode 100644 index a308fc0..0000000 --- a/core/java/com/google/android/gdata/client/AndroidXmlParserFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.google.android.gdata.client; - -import com.google.wireless.gdata.parser.xml.XmlParserFactory; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import android.util.Xml; - -/** - * XmlParserFactory for the Android platform. - */ -public class AndroidXmlParserFactory implements XmlParserFactory { - - /* - * (non-javadoc) - * @see XmlParserFactory#createParser - */ - public XmlPullParser createParser() throws XmlPullParserException { - return Xml.newPullParser(); - } - - /* - * (non-javadoc) - * @see XmlParserFactory#createSerializer - */ - public XmlSerializer createSerializer() throws XmlPullParserException { - return Xml.newSerializer(); - } -} diff --git a/core/java/com/google/android/gdata/client/QueryParamsImpl.java b/core/java/com/google/android/gdata/client/QueryParamsImpl.java deleted file mode 100644 index fbe0d22..0000000 --- a/core/java/com/google/android/gdata/client/QueryParamsImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.google.android.gdata.client; - -import com.google.wireless.gdata.client.QueryParams; - -import android.text.TextUtils; -import android.util.Log; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Simple implementation of the QueryParams interface. - */ -// TODO: deal with categories -public class QueryParamsImpl extends QueryParams { - - private final Map<String,String> mParams = new HashMap<String,String>(); - - /** - * Creates a new empty QueryParamsImpl. - */ - public QueryParamsImpl() { - } - - @Override - public void clear() { - setEntryId(null); - mParams.clear(); - } - - @Override - public String generateQueryUrl(String feedUrl) { - - if (TextUtils.isEmpty(getEntryId()) && - mParams.isEmpty()) { - // nothing to do - return feedUrl; - } - - // handle entry IDs - if (!TextUtils.isEmpty(getEntryId())) { - if (!mParams.isEmpty()) { - throw new IllegalStateException("Cannot set both an entry ID " - + "and other query paramters."); - } - return feedUrl + '/' + getEntryId(); - } - - // otherwise, append the querystring params. - StringBuilder sb = new StringBuilder(); - sb.append(feedUrl); - Set<String> params = mParams.keySet(); - boolean first = true; - if (feedUrl.contains("?")) { - first = false; - } else { - sb.append('?'); - } - for (String param : params) { - String value = mParams.get(param); - if (value == null) continue; - if (first) { - first = false; - } else { - sb.append('&'); - } - sb.append(param); - sb.append('='); - - String encodedValue = null; - - try { - encodedValue = URLEncoder.encode(value, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - // should not happen. - Log.w("QueryParamsImpl", - "UTF-8 not supported -- should not happen. " - + "Using default encoding.", uee); - encodedValue = URLEncoder.encode(value); - } - sb.append(encodedValue); - } - return sb.toString(); - } - - @Override - public String getParamValue(String param) { - if (!(mParams.containsKey(param))) { - return null; - } - return mParams.get(param); - } - - @Override - public void setParamValue(String param, String value) { - mParams.put(param, value); - } - -} diff --git a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java deleted file mode 100644 index 3721fa4..0000000 --- a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java +++ /dev/null @@ -1,603 +0,0 @@ -// Copyright 2007 The Android Open Source Project - -package com.google.android.gdata2.client; - -import com.google.android.net.GoogleHttpClient; -import com.google.wireless.gdata2.client.GDataClient; -import com.google.wireless.gdata2.client.HttpException; -import com.google.wireless.gdata2.client.QueryParams; -import com.google.wireless.gdata2.data.StringUtils; -import com.google.wireless.gdata2.parser.ParseException; -import com.google.wireless.gdata2.serializer.GDataSerializer; -import com.google.android.gdata2.client.QueryParamsImpl; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.params.HttpParams; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.entity.ByteArrayEntity; - -import android.content.ContentResolver; -import android.content.Context; -import android.net.http.AndroidHttpClient; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; -import android.os.SystemProperties; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.io.BufferedInputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; - -/** - * 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. - */ -public class AndroidGDataClient implements GDataClient { - - private static final String TAG = "GDataClient"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; - - private static final String X_HTTP_METHOD_OVERRIDE = - "X-HTTP-Method-Override"; - - private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.2"; - - private static final int MAX_REDIRECTS = 10; - private static String DEFAULT_GDATA_VERSION = "2.0"; - - // boolean system property that can be used to control whether or not - // requests/responses are gzip'd. - private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip"; - - private String mGDataVersion; - private final GoogleHttpClient mHttpClient; - private ContentResolver mResolver; - - /** - * Interface for creating HTTP requests. Used by - * {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for - * changing the URI after creation, e.g., when you want to follow a redirect. - */ - private interface HttpRequestCreator { - HttpUriRequest createRequest(URI uri); - } - - private static class GetRequestCreator implements HttpRequestCreator { - public GetRequestCreator() { - } - - public HttpUriRequest createRequest(URI uri) { - HttpGet get = new HttpGet(uri); - return get; - } - } - - private static class PostRequestCreator implements HttpRequestCreator { - private final String mMethodOverride; - private final HttpEntity mEntity; - public PostRequestCreator(String methodOverride, HttpEntity entity) { - mMethodOverride = methodOverride; - mEntity = entity; - } - - public HttpUriRequest createRequest(URI uri) { - HttpPost post = new HttpPost(uri); - if (mMethodOverride != null) { - post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride); - } - post.setEntity(mEntity); - return post; - } - } - - // MAJOR TODO: make this work across redirects (if we can reset the InputStream). - // OR, read the bits into a local buffer (yuck, the media could be large). - private static class MediaPutRequestCreator implements HttpRequestCreator { - private final InputStream mMediaInputStream; - private final String mContentType; - public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) { - mMediaInputStream = mediaInputStream; - mContentType = contentType; - } - - public HttpUriRequest createRequest(URI uri) { - HttpPost post = new HttpPost(uri); - post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT"); - // mMediaInputStream.reset(); - InputStreamEntity entity = new InputStreamEntity(mMediaInputStream, - -1 /* read until EOF */); - entity.setContentType(mContentType); - post.setEntity(entity); - return post; - } - } - - - /** - * 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. - */ - public AndroidGDataClient(Context context) { - this(context, DEFAULT_USER_AGENT_APP_VERSION); - } - - /** - * 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. - */ - public AndroidGDataClient(Context context, String appAndVersion) { - this(context, appAndVersion, DEFAULT_GDATA_VERSION); - } - - /** - * 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. - * @param gdataVersion The gdata service version that should be - * used, e.g. "2.0" - * - */ - public AndroidGDataClient(Context context, String appAndVersion, String gdataVersion) { - mHttpClient = new GoogleHttpClient(context, appAndVersion, - true /* gzip capable */); - mHttpClient.enableCurlLogging(TAG, Log.VERBOSE); - mResolver = context.getContentResolver(); - mGDataVersion = gdataVersion; - } - - - public void close() { - mHttpClient.close(); - } - - /* - * (non-Javadoc) - * @see GDataClient#encodeUri(java.lang.String) - */ - public String encodeUri(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; - } - - /* - * (non-Javadoc) - * @see com.google.wireless.gdata.client.GDataClient#createQueryParams() - */ - public QueryParams createQueryParams() { - return new QueryParamsImpl(); - } - - // follows redirects - private InputStream createAndExecuteMethod(HttpRequestCreator creator, - String uriString, - String authToken, - String eTag, - String protocolVersion) - throws HttpException, IOException { - - 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); - - if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) { - 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); - } - - // while by default we have a 2.0 in this variable, it is possible to construct - // a client that has an empty version field, to work with 1.0 services. - if (!TextUtils.isEmpty(mGDataVersion)) { - request.addHeader("GDataVersion", mGDataVersion); - } - - // if we have a passed down eTag value, we need to add several headers - if (!TextUtils.isEmpty(eTag)) { - String method = request.getMethod(); - Header overrideMethodHeader = request.getFirstHeader(X_HTTP_METHOD_OVERRIDE); - if (overrideMethodHeader != null) { - method = overrideMethodHeader.getValue(); - } - if ("GET".equals(method)) { - // add the none match header, if the resource is not changed - // this request will result in a 304 now. - request.addHeader("If-None-Match", eTag); - } else if ("DELETE".equals(method) - || "PUT".equals(method)) { - // now we send an if-match, but only if the passed in eTag is a strong eTag - // as this only makes sense for a strong eTag - if (!eTag.startsWith("W/")) { - request.addHeader("If-Match", eTag); - } - } - } - - 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 */); - } - - /* - * (non-Javadoc) - * @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String) - */ - public InputStream getFeedAsStream(String feedUrl, - String authToken, - String eTag, - String protocolVersion) - throws HttpException, IOException { - - InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken, eTag, protocolVersion); - if (in != null) { - return in; - } - throw new IOException("Unable to access feed."); - } - - /** - * 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 - */ - private InputStream logInputStreamContents(InputStream in) 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 InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken, String eTag, String protocolVersion) - throws HttpException, IOException { - - InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken, eTag, protocolVersion); - - if (in != null) { - return in; - } - throw new IOException("Unable to access media entry."); - } - - /* (non-Javadoc) - * @see GDataClient#createEntry - */ - public InputStream createEntry(String feedUrl, - String authToken, - String protocolVersion, - GDataSerializer entry) - throws HttpException, IOException { - - HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE); - InputStream in = createAndExecuteMethod( - new PostRequestCreator(null /* override */, entity), - feedUrl, - authToken, - null, - protocolVersion); - if (in != null) { - return in; - } - throw new IOException("Unable to create entry."); - } - - /* (non-Javadoc) - * @see GDataClient#updateEntry - */ - public InputStream updateEntry(String editUri, - String authToken, - String eTag, - String protocolVersion, - GDataSerializer entry) - throws HttpException, IOException { - HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE); - final String method = entry.getSupportsPartial() ? "PATCH" : "PUT"; - InputStream in = createAndExecuteMethod( - new PostRequestCreator(method, entity), - editUri, - authToken, - eTag, - protocolVersion); - if (in != null) { - return in; - } - throw new IOException("Unable to update entry."); - } - - /* (non-Javadoc) - * @see GDataClient#deleteEntry - */ - public void deleteEntry(String editUri, String authToken, String eTag) - throws HttpException, IOException { - 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, - eTag, - null /* protocolVersion, not required for a delete */); - if (in == null) { - throw new IOException("Unable to delete entry."); - } - try { - in.close(); - } catch (IOException ioe) { - // ignore - } - } - - public InputStream updateMediaEntry(String editUri, String authToken, String eTag, - String protocolVersion, InputStream mediaEntryInputStream, String contentType) - throws HttpException, IOException { - InputStream in = createAndExecuteMethod( - new MediaPutRequestCreator(mediaEntryInputStream, contentType), - editUri, - authToken, - eTag, - protocolVersion); - if (in != null) { - return in; - } - throw new IOException("Unable to write media entry."); - } - - private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException { - 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; - if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) { - entity = new ByteArrayEntity(entryBytes); - } else { - entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver); - } - - entity.setContentType(entry.getContentType()); - return entity; - } - - /** - * Connects to a GData server (specified by the batchUrl) and submits a - * batch for processing. The response from the server is returned as an - * {@link InputStream}. The caller is responsible for calling - * {@link InputStream#close()} on the returned {@link InputStream}. - * - * @param batchUrl The batch url to which the batch is submitted. - * @param authToken the authentication token that should be used when - * submitting the batch. - * @param protocolVersion The version of the protocol that - * should be used for this request. - * @param batch The batch of entries to submit. - * @throws IOException Thrown if an io error occurs while communicating with - * the service. - * @throws HttpException if the service returns an error response. - */ - public InputStream submitBatch(String batchUrl, - String authToken, - String protocolVersion, - GDataSerializer batch) - throws HttpException, IOException - { - HttpEntity entity = createEntityForEntry(batch, GDataSerializer.FORMAT_BATCH); - InputStream in = createAndExecuteMethod( - new PostRequestCreator("POST", entity), - batchUrl, - authToken, - null, - protocolVersion); - if (in != null) { - return in; - } - throw new IOException("Unable to process batch request."); - } -} diff --git a/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java deleted file mode 100644 index f097706..0000000 --- a/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.google.android.gdata2.client; - -import com.google.wireless.gdata2.parser.xml.XmlParserFactory; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import android.util.Xml; - -/** - * XmlParserFactory for the Android platform. - */ -public class AndroidXmlParserFactory implements XmlParserFactory { - - /* - * (non-javadoc) - * @see XmlParserFactory#createParser - */ - public XmlPullParser createParser() throws XmlPullParserException { - return Xml.newPullParser(); - } - - /* - * (non-javadoc) - * @see XmlParserFactory#createSerializer - */ - public XmlSerializer createSerializer() throws XmlPullParserException { - return Xml.newSerializer(); - } -} diff --git a/core/java/com/google/android/gdata2/client/QueryParamsImpl.java b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java deleted file mode 100644 index a26f4ce..0000000 --- a/core/java/com/google/android/gdata2/client/QueryParamsImpl.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.google.android.gdata2.client; -import com.google.wireless.gdata2.client.QueryParams; - -import android.text.TextUtils; -import android.util.Log; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * Simple implementation of the QueryParams interface. - */ -// TODO: deal with categories -public class QueryParamsImpl extends QueryParams { - - private final Map<String,String> mParams = new HashMap<String,String>(); - - /** - * Creates a new empty QueryParamsImpl. - */ - public QueryParamsImpl() { - } - - @Override - public void clear() { - setEntryId(null); - mParams.clear(); - } - - @Override - public String generateQueryUrl(String feedUrl) { - - if (TextUtils.isEmpty(getEntryId()) && - mParams.isEmpty()) { - // nothing to do - return feedUrl; - } - - // handle entry IDs - if (!TextUtils.isEmpty(getEntryId())) { - if (!mParams.isEmpty()) { - throw new IllegalStateException("Cannot set both an entry ID " - + "and other query paramters."); - } - return feedUrl + '/' + getEntryId(); - } - - // otherwise, append the querystring params. - StringBuilder sb = new StringBuilder(); - sb.append(feedUrl); - Set<String> params = mParams.keySet(); - boolean first = true; - if (feedUrl.contains("?")) { - first = false; - } else { - sb.append('?'); - } - for (String param : params) { - if (first) { - first = false; - } else { - sb.append('&'); - } - sb.append(param); - sb.append('='); - String value = mParams.get(param); - String encodedValue = null; - - try { - encodedValue = URLEncoder.encode(value, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - // should not happen. - Log.w("QueryParamsImpl", - "UTF-8 not supported -- should not happen. " - + "Using default encoding.", uee); - encodedValue = URLEncoder.encode(value); - } - sb.append(encodedValue); - } - return sb.toString(); - } - - @Override - public String getParamValue(String param) { - if (!(mParams.containsKey(param))) { - return null; - } - return mParams.get(param); - } - - @Override - public void setParamValue(String param, String value) { - mParams.put(param, value); - } - -} |
