My favorites | English | Sign in

Google Documents List Data API v3.0 (Labs)

Java Language Guide (v3.0)

In addition to providing some background on the capabilities of the Documents List Data API, this guide provides examples for interacting with the API using the Java client library. For help setting up the client library, see Getting Started with the Google Data Java Client Library. If you're interested in understanding more about the underlying protocol used by the Java client library to interact with the Documents List, please see the protocol guide.

Important: The Google Documents List Data API v3.0 is in Labs, and its features might change unexpectedly until it graduates. Version 2.0 is the latest graduated version.

Contents

  1. Audience
  2. Getting started
  3. Authenticating to the Documents List API
    1. AuthSub for web applications
    2. OAuth for web applications
    3. ClientLogin for installed/mobile applications
  4. Retrieving a list of documents
  5. Searching the documents feed
    1. Category queries
    2. Performing title queries
    3. Performing a full text query
  6. Retrieving folder contents
  7. Uploading documents
    1. Creating an empty document
    2. Uploading documents with content
    3. Creating/uploading documents to folders
  8. Updating documents
    1. Updating metadata
    2. Replacing a document's content
    3. Updating a document's content and metadata
  9. Deleting documents and folders
    1. Trashing a document or folder
    2. Deleting a document or folder New
  1. Downloading documents
    1. Exporting word processor documents
    2. Exporting presentations
    3. Exporting spreadsheets
      1. Exporting spreadsheets using AuthSub/OAuth
      2. Exporting spreadsheets using ClientLogin
    4. Downloading PDFs New
  2. Folder management
    1. Creating folders
    2. Creating a subfolder
    3. Moving documents/folders
      1. Moving a resource into a folder
      2. Moving a resource out of a folder
  3. Modifying Document and Folder Sharing Permissions
    1. Retrieving the ACL feed
    2. Modifying the ACL feed
      1. Group/Domain-level sharing New
    3. Updating sharing permissions
    4. Removing sharing permissions
  4. Document Revisions New
    1. Retrieving document revisions
    2. Downloading a revision

Audience

This document is intended for developers who want to write client applications using the Google Data Java client library that can interact with Google Documents.

Getting started

Google Documents uses Google Accounts for authentication, so if you have a Google account you are all set. Otherwise, you can create a new account.

Installing the library

For help setting up and installing the client library, see the Getting Started with the Google Data Java Client Library. If you're using Eclipse, that article also explains how to setup your project using the Google Data APIs Eclipse plugin. Here's what you need to get started:

  1. Install Java 1.5 or higher
  2. Download the client library (the latest version of gdata-src.java.zip)
  3. Download the list of dependencies.
  4. Download the samples applications (the latest version of gdata-samples.java.zip)

After installing the .jars, you'll find the classes you need to get started in the java/lib/gdata-document-3.0.jar and java/lib/gdata-client-1.0.jar jar files. Since the Documents List API also extends MediaService, you'll need to include java/lib/gdata-media-1.0.jar and the JavaMail mail.jar from the list of dependencies above.

Running the sample application

A full working sample application lis ocated in /java/sample/docs subdirectory of the gdata-samples.java.zip download. The source is also available at /trunk/java/sample/docs/DocumentListDemo.java in the SVN repository accessible from the Source tab. The DocumentListDemo.java allows the user to perform a number of operations which demonstrate how to use the Documents List feed.

Starting your own project

Tip: See the article Using Eclipse with Google Data APIs for quick setup with our Eclipse plugin.

Depending on your application's needs, you'll need serveral imports. It's recommend to include the following:

import com.google.gdata.client.*;
import com.google.gdata.client.docs.*;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.acl.*;
import com.google.gdata.data.docs.*;
import com.google.gdata.data.extensions.*;
import com.google.gdata.util.*;

Next, you will also need to setup a DocsService object, which represents a client connection (with authentication) to the Documents List API:

DocsService client = new DocsService("yourCo-yourAppName-v1");

The applicationName argument should follow the format: company-applicationname-version. This parameter is used for logging purposes.

Note: The rest of the guide assumes you created a DocsService in the variable client.

Back to top

Authenticating to the Documents List API

The Java client library can be used to work with either public or private feeds. The Documents List Data API provides access to private feeds which require authentication with the documents servers. This can be done via ClientLogin username/password authentication, AuthSub, or OAuth.

Note: The API only offers private feeds at the moment. Your application must perform authentication to issue requests against the Documents List.

Please see the Google Data APIs Authentication Overview for more information on AuthSub, OAuth, and ClientLogin.

AuthSub for web applications

AuthSub Authentication for Web Applications should be used by client applications which need to authenticate their users to Google accounts. The operator does not need access to the username and password for the Google Documents user - only an AuthSub token is required.

View instructions for incorporating AuthSub into your web application Show rest of description Hide rest of description

OAuth for web applications

OAuth can be used as an alternative to AuthSub, and is intended for web applications. OAuth is similar to using the secure and registered mode of AuthSub in that all data requests must be digitally signed and you must register your domain.

View instructions for incorporating OAuth into your installed application Show rest of description Hide rest of description

ClientLogin for installed/mobile applications

ClientLogin should be used by installed or mobile applications which need to authenticate their users to Google accounts. On first run, your application prompts the user for their username/password. On subsequent requests, an authentication token is referenced.

View instructions for incorporating ClientLogin into your installed application Show rest of description Hide rest of description

Back to top

Retrieving a list of documents

To fetch a feed containing a list of the currently authenticated user's documents, send an authenticated GET request to the following URL:

http://docs.google.com/feeds/default/private/full

The result is a feed that lists all of that user's documents; each entry in the feed represents an object (spreadsheet, presentation, word processor document, pdf, folder, etc.). Again, this feed is only accessible after Authenticating to the Documents List API.

Here is an example of printing out the user's entire document list:

public void showAllDocs() throws IOException, ServiceException {
  URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/");
  DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);

  for (DocumentListEntry entry : feed.getEntries()) {
    printEntry(entry);
  }
}

public void printEntry(DocumentListEntry entry) {
  String resourceId = entry.getResourceId();
  String docType = entry.getType();

  System.out.println("'" + entry.getTitle().getPlainText() + "' (" + docType + ")");
  System.out.println("  link to Google Docs: " + entry.getDocumentLink().getHref());
  System.out.println("  resource id: " + resourceId);
  System.out.println("  doc id: " + entry.getDocId();

  // print the parent folder the document is in
  if (!entry.getParentLinks().isEmpty()) {
    System.out.println("  Parent folders: ");
    for (Link link : entry.getParentLinks()) {
      System.out.println("    --" + link.getTitle() + " - " + link.getHref());
    }
  }

  // print the timestamp the document was last viewed
  DateTime lastViewed = entry.getLastViewed();
  if (lastViewed != null) {
    System.out.println("  last viewed: " + lastViewed.toUiString());
  }

  // print who made the last modification
  LastModifiedBy lastModifiedBy = entry.getLastModifiedBy();
  if (lastModifiedBy != null) {
    System.out.println("  updated by: " +
        lastModifiedBy.getName() + " - " + lastModifiedBy.getEmail());
  }

  // Files such as PDFs take up quota
  if (entry.getQuotaBytesUsed() > 0) {
    System.out.println("Quota used: " + entry.getQuotaBytesUsed() + " bytes");
  }

  // print other useful metadata
  System.out.println("  last updated: " + entry.getUpdated().toUiString());
  System.out.println("  viewed by user? " + entry.isViewed());
  System.out.println("  writersCanInvite? " + entry.isWritersCanInvite().toString());
  System.out.println("  hidden? " + entry.isHidden());
  System.out.println("  starred? " + entry.isStarred());
  System.out.println("  trashed? " + entry.isTrashed());
  System.out.println();
}

The resulting DocumentListFeed object feed represents a response from the server. Among other things, this feed contains a list of DocumentListEntry objects (feed.getEntries()), each of which represents a single document or folder. DocumentListEntry encapsulates the information shown in the protocol document.

Document resource ID

This document often refers to the notion of a "document ID" and a document "resource ID". An object's resource ID can be found in the DocumentListEntry as entry.getResourceId(). Its value can be used in a number of places, most notably when exporting the document or querying for the entry again. Each resource ID includes the type of document and the document's unique ID:

<gd:resourceId>type:docID</gd:resourceId>

The doc ID can be fetched with entry.getDocId(), though it is recommend that you store a document's full resource ID rather than just the document ID because the type is contained within the entire resource ID.

Back to top

Searching the documents feed

You can search the Document List using some of the standard Google Data API query parameters. Categories are used to restrict the type of document (spreadsheet, folder, etc.) returned. The full-text query string (q parameter) is used to search the content of all the documents. More detailed information on parameters specific to the Documents List can be found in the Documents List Data API Reference Guide.

The following code is used in all of the examples below to print out the feed results to the command line.

public void printDocuments(DocumentListFeed feed) {
  for (DocumentListEntry entry : feed.getEntries()) {
    String resourceId = entry.getResourceId();
    System.out.println(" -- Document(" + resourceId + "/" + entry.getTitle().getPlainText() + ")");
  }
}

Retrieving all word processor documents

A list of only word processor documents can be retrieved by using the document category as follows:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/-/document");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

Retrieving all spreadsheets

A list of only spreadsheets can be retrieved by using the spreadsheet category as follows:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/-/spreadsheet");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

Retrieving a list of owned presentations

A list of presentations the current logged in user owns can be retrieved by using the presentation and mine categories as follows:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/-/presentation/mine");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

Retrieving a list of folders

A list of folders can be retrieved by using the folder category:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/-/folder");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

Retrieving a list of trashed documents

A list of trashed objects can be retrieved by using the trashed category:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/-/trashed");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

To include a list of trashed documents along with normal queries results, use the showdeleted parameter:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/?showdeleted=true");
DocumentListFeed feed = client.getFeed(feedUri, DocumentListFeed.class);
printDocuments(feed);

Tip: Category queries can work for other document types as well. For a list of possible categories, see the reference guide.

Retrieving a document by an exact title match

It is possible to retrieve documents by matching on their title instead of their entire contents. To do this, you can also use the DocumentQuery class to construct complex queries for the Documents List feed.

This example uses the title parameter and title-exact parameter to indicate a full, explicit title match. Since this parameter is case-insensitive or multiple docs could have the same title, a feed is returned.

The following examples searches for the first 10 documents matching the title "Test", and orders the results alphabetically:

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/");
DocumentQuery query = new DocumentQuery(feedUri);
query.setSortMode("title");
query.setTitleQuery("Test");
query.setTitleExact(true);
query.setMaxResults(10);
DocumentListFeed feed = client.getFeed(query, DocumentListFeed.class);
printDocuments(feed);

Note: title-exact queries are case-insenstive.

Performing a full text query

You can search the contents of documents by using the q parameter or the setFullTextQuery() method of the DocumentQuery object.

URL feedUri = new URL("http://docs.google.com/feeds/default/private/full/");
DocumentQuery query = new DocumentQuery(feedUri);
query.setFullTextQuery("Something to search for");
DocumentListFeed feed = client.getFeed(query, DocumentListFeed.class);
printDocuments(feed);

This snippet searches the entire contents of every document for the string "Something to search for" and returns all documents where this string is found. This is different than searching just the title of every document, which can be done as described in the section Retrieving a document by an exact title match.

Back to top

Retrieving folder contents

To retrieve a list of objets in a particular folder, send an HTTP GET to the folder's feed URL. That URL will look something like:

http://docs.google.com/feeds/default/private/full/folder%3Afolder_id/contents

Each folder Atom entry in the documents list will contain such a link. A folder's content feed can be found in the folderEntry's <content type="application/atom+xml;type=feed">'s 'src' attribute. Here is an example:

String foldersFeedUri = ((MediaContent) folderEntry.getContent()).getUri();

// You can also contruct the foldersFeedUri manually if you know the folder's resource id (e.g. folder%3Afolder_id)
// URL foldersFeedUri = new URL("http://docs.google.com/feeds/default/private/full/folder%3Afolder_id/contents");

DocumentQuery query = new DocumentQuery(feedUri);
query.setFullTextQuery("Something to search for");
DocumentListFeed feed = client.getFeed(query, DocumentListFeed.class);
printDocuments(feed);

By default, folder entries will also be returned within the folders feed (e.g. you don't have to include the showfolders=true parameter. The folders feed can also be queried using the query parameters defined in the Documents List Data API Reference Guide.

Back to top

Uploading documents

Creating an empty document

This example creates a new word processor document in the Documents List feed by creating a DocumentListEntry object containining metadata for the document.

DocumentListEntry createdEntry = null;

// Create an empty word processor document
createdEntry = createNewDocument("NewDocTitle", "document");
System.out.println("Document now online @ :" + createdEntry.getDocumentLink().getHref());

// Create an empty presentation
createdEntry = createNewDocument("NewPresentationTitle", "presentation");
System.out.println("Presentation now online @ :" + createdEntry.getDocumentLink().getHref());

// Create an empty spreadsheet
createdEntry = createNewDocument("NewSpreadsheetTitle", "spreadsheet");
System.out.println("Spreadsheet now online @ :" + createdEntry.getDocumentLink().getHref());

public DocumentListEntry createNewDocument(String title, String type)
    throws IOException, ServiceException {
  DocumentListEntry newEntry = null;
  if (type.equals("document")) {
    newEntry = new DocumentEntry();
  } else if (type.equals("presentation")) {
    newEntry = new PresentationEntry();
  } else if (type.equals("spreadsheet")) {
    newEntry = new SpreadsheetEntry();
  }
  newEntry.setTitle(new PlainTextConstruct(title));

  // Prevent collaborators from sharing the document with others?
  // newEntry.setWritersCanInvite(false);

  // You can also hide the document on creation
  // newEntry.setHidden(true);

  return client.insert(new URL("http://docs.google.com/feeds/default/private/full/"), newEntry);
}

Uploading documents with content

To upload a document to the server you can attach the file to the new DocumentListEntry using the setFile() method. Once the file is associated with this entry, it's contents will be sent to the server when you insert the DocumentListEntry.

The example below shows how to upload a file when given the absolute path of a file. Note that the mime-type sent to the server is inferred from the file's extension.

DocumentListEntry uploadedEntry = uploadFile("/path/to/your/file.doc", "TitleToUse");
System.out.println("Document now online @ :" + uploadedEntry.getDocumentLink().getHref());

public DocumentListEntry uploadFile(String filepath, String title)
    throws IOException, ServiceException  {
  File file = new File(filepath);
  String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();

  DocumentListEntry newDocument = new DocumentListEntry();
  newDocument.setFile(file, mimeType);
  newDocument.setTitle(new PlainTextConstruct(title));

  // Prevent collaborators from sharing the document with others?
  // newDocument.setWritersCanInvite(false);

  return client.insert(new URL("http://docs.google.com/feeds/default/private/full/"), newDocument);
}

Note: that the above sample sets the name of the document to "TitleToUse", but you are free to choose a different name by passing in a string to the PlainTextConstruct constructor.

Creating/uploading documents to folders

Creating an empty document in a folder

To create an empty document, presentation, or spreadsheet in an existing folder, you need to make a POST request to the folder's Atom content src URL. One way to do this is to overload our createNewDocument() method to accept the URL of the parent folder. Here, it assumed that folderEntry is a DocumentListEntry object representing the destination folder.

String destFolderUrl = ((MediaContent) folderEntry.getContent()).getUri();

// Alternatively, you can manually construct the destFolderUrl (e.g. if you only have the folder's resource ID):
// URL destFolderUrl = new URL("http://docs.google.com/feeds/default/private/full/FOLDER_RESOURCE_ID/contents");

DocumentListEntry createdEntry = createNewDocument("NewDocument", "document", destFolderUrl);
System.out.println("Document now online in folder '" +
    folderEntry.getTitle().getPlainText() + "' @ :" + createdEntry.getDocumentLink().getHref());

public DocumentListEntry createNewDocument(String title, String type, URL uri)
    throws IOException, ServiceException {
  DocumentListEntry newEntry = null;
  if (type.equals("document")) {
    newEntry = new DocumentEntry();
  } else if (type.equals("presentation")) {
    newEntry = new PresentationEntry();
  } else if (type.equals("spreadsheet")) {
    newEntry = new SpreadsheetEntry();
  }
  newEntry.setTitle(new PlainTextConstruct(title));

  return client.insert(uri, newEntry);
}

public DocumentListEntry createNewDocument(String title, String type)
    throws MalformedURLException, IOException, ServiceException {
  return createNewDocument(title, type, new URL("http://docs.google.com/feeds/default/private/full/"));
}

Uploading a document to a folder

Similar to creating a document inside a folder, you can upload an existing document, presentation, or spreadsheet into a folder by overloading the uploadFile() method (defined above) to accept the URL of the destination folder. It assumed that folderEntry is a valid DocumentListEntry object representing the folder you wish to upload to.

String destFolderUrl = ((MediaContent) folderEntry.getContent()).getUri();

DocumentListEntry uploadedEntry = uploadFile("/path/to/your/file.doc", "TitleToUse", destFolderUrl);
System.out.println("Document now online in folder '" +
    folderEntry.getTitle().getPlainText() + "' @ :" + uploadedEntry.getDocumentLink().getHref());

// Uploads a file to a particular folder specified by the URL argument
public DocumentListEntry uploadFile(String filepath, String title, URL uri)
    throws IOException, ServiceException  {
  File file = new File(filepath);
  DocumentListEntry newDocument = new DocumentListEntry();
  String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
  newDocument.setFile(new File(filepath), mimeType);
  newDocument.setTitle(new PlainTextConstruct(title));

  return client.insert(uri, newDocument);
}

// Uploads a file to the root documents list
public DocumentListEntry uploadFile(String filepath, String title)
    throws IOException, ServiceException  {
  return uploadFile(filepath, title, new URL("http://docs.google.com/feeds/default/private/full/"));
}

Back to top

Updating documents

Updating documents requires the use of ETags to make sure you are not overwriting another client's changes. An entry's ETag can be found by calling documentEntry.getEtag().

Note: If you want to trash the document regardless of whether someone else has updated it since you last retrieved it, substitute "*" for the entry's ETag value. That will force a unconditional delete on the entry.

For more information on ETags, see the Google Data APIs reference guide.

Updating metadata

Here is an example of updating a document's metadata, but leaving its content unchanged. The document's name will be changed to 'Updated Title'. It is assumed you have already fetched the DocumentListEntry in entry.

entry.setTitle(new PlainTextConstruct("Updated Title"));
DocumentListEntry updatedEntry = entry.update();

// Alternatively, you can use the DocsService object's update():
// DocumentListEntry updatedEntry = client.update(new URL(entry.getEditLink().getHref()), entry, entry.getEtag());

System.out.println(updatedEntry.getTitle().getPlainText());

If the update succeeds, then the server returns an HTTP 200 OK status code, and a copy of the updated entry. If the update fails because the ETag you specified doesn't match the current ETag on the entry (which implies that the entry has changed on the server since you last retrieved it), then the server returns an HTTP 412 Precondition Failed status code. In that case, you should fetch the lastest entry from the server, make your modifications, and attempt the update again.

Replacing a document's content

To update a document's content, use the DocumentListEntry's updateMedia() method. The following example replaces the document's content with "updated content". It is assumed you have already fetched the entry.

entry.setMediaSource(new MediaByteArraySource("updated content".getBytes(), "text/plain"));
DocumentListEntry updatedEntry = entry.updateMedia(true);

Updating a document's content and metadata

To update a document's content and metadata at the same time, use the DocumentListEntry's updateMedia() method as in the previous example, but also update the entry itself.

The following example replaces the document's content with the contents of newer_data.doc, changes the document's title to 'Newer Title', and prevents collaboratores from further sharing the document with other users. It is assumed you have already fetched the entry.

File file = new File("/path/to/file/newer_data.doc");
String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
entry.setMediaSource(new MediaFileSource(file, mimeType));
entry.setTitle(new PlainTextConstruct("Newer Title"));
entry.setWritersCanInvite(false);
DocumentListEntry updatedEntry = entry.updateMedia(true);

Back to top

Trashing documents and folders

Trashing/deleting documents or folders requires the use of ETags to make sure you are not overwriting another client's changes. An entry's ETag can be found by calling entry.getEtag().

Note: If you want to trash the document regardless of whether someone else has updated it since you last retrieved it, substitute "*" for the entry's ETag value. That will force a unconditional delete on the entry.

For more information on ETags, see the Google Data APIs reference guide.

Trashing a document or folder

Trashing a document moves it to the trash. You can call the delete() method on the retrieved DocumentListEntry object:

entry.delete()

Alternatively, you can call the service object's delete method and pass in the entry's edit link and ETag:

client.delete(new URL(entry.getEditLink().getHref()), entry.getEtag());

Lastly, if you don't have the entry as a DocumentListEntry object, construct the edit link manually using the resource id:

client.delete(new URL("http://docs.google.com/feeds/default/private/full/RESOURCE_ID"), "*");

If the delete succeeds, then the server returns an HTTP 200 OK status code. If the delete fails because the ETag you specified doesn't match the current ETag on the entry (which implies that the entry has changed on the server since you last retrieved it), then the server returns an HTTP 412 Precondition Failed status code. In that case, you should fetch the lastest entry from the server, make your modifications, and attempt the update again.

Deleting a document or folder

Deleting a document or folder permanently removes the object from the user's documents list. The process for deleting a document is similar to trashing a document, just include the delete=true parameter. Use the DocsService object's delete() method to pass that argument in the URL:

client.delete(new URL(entry.getEditLink().getHref() + "?delete=true"), entry.getEtag());

Back to top

Downloading and exporting documents

To export documents from the Documents List feed, you need the Atom entry of the document or the document, spreadsheet, or presentation's resource id (e.g. spreadsheet:12345). Note, each type of document has a valid set of export formats.

Important: If you wish to use the same OAuth/AuthSub token to download all types of documents, request a multi-scoped token good for docs.google.com, spreadsheets.google.com, and docs.googleusercontent.com. For example, the AuthSub/OAuth scope parameter would be: scope=http://docs.google.com/feeds/ http://spreadsheets.google.com/feeds/ http://docs.googleusercontent.com/.

The examples throughout this section will reuse the following downloadFile() helper, which downloads the file to local disk:

public void downloadFile(String exportUrl, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  System.out.println("Exporting document from: " + exportUrl);

  MediaContent mc = new MediaContent();
  mc.setUri(exportUrl);
  MediaSource ms = client.getMedia(mc);

  InputStream inStream = null;
  FileOutputStream outStream = null;

  try {
    inStream = ms.getInputStream();
    outStream = new FileOutputStream(filepath);

    int c;
    while ((c = inStream.read()) != -1) {
      outStream.write(c);
    }
  } finally {
    if (inStream != null) {
      inStream.close();
    }
    if (outStream != null) {
      outStream.flush();
      outStream.close();
    }
  }
}

Exporting word processor documents

The following example fetches first document from the user's doclist and exports the DocumentListEntry object as a .doc. . Note, the exportFormat is inferred from the save-to file extension, in this case a .doc. Additionally, there's another helper that takes a document's resource ID and manually constructs the Export url.

URL feedUrl = new URL("http://docs.google.com/feeds/default/private/full/-/document?max-results=1");
List<DocumentListEntry> entries  = client.getFeed(feedUrl, DocumentListFeed.class).getEntries();

downloadDocument(entries.get(0), "/path/to/export/to/myDoc.doc");

// OR
// downloadDocument("document:dfrkj84g_9128gtvh8nt", "/path/to/export/to/myDoc.doc");

public void downloadDocument(String resourceId, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String docId = resourceId.substring(resourceId.lastIndexOf(":") + 1);
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = "http://docs.google.com/feeds/download/documents/Export?docId=" +
      docId + "&exportFormat=" + fileExtension;
  downloadFile(exportUrl, filepath);
}

public void downloadDocument(DocumentListEntry entry, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = ((MediaContent) entry.getContent()).getUri() + "&exportFormat=" + fileExtension;
  downloadFile(exportUrl, filepath);
}

Exporting presentations

The same idea can be applied to exporting presentations. The following example fetches first presentation from the user's doclist and exports the DocumentListEntry object as a .pdf. Additionally, there's another helper that would take a presentations's resource ID and manually constructs the Export url.

URL feedUrl = new URL("http://docs.google.com/feeds/default/private/full/-/presentation?max-results=1");
List<DocumentListEntry> entries  = client.getFeed(feedUrl, DocumentListFeed.class).getEntries();

downloadPresentation(entries.get(0), "/path/to/export/to/myPresentation.pdf");

// OR
// downloadPresentation("presentation:dfrkj84g_9128gtvh8nt", "/path/to/export/to/myPresentation.pdf");

public void downloadPresentation(String resourceId, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String docId = resourceId.substring(resourceId.lastIndexOf(":") + 1);
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = "http://docs.google.com/feeds/download/presentations/Export?docId=" +
      docId + "&exportFormat=" + fileExtension;
  downloadFile(exportUrl, filepath);
}

public void downloadPresentation(DocumentListEntry entry, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = ((MediaContent) entry.getContent()).getUri() + "&exportFormat=" + fileExtension;
  downloadFile(exportUrl, filepath);
}

Exporting spreadsheets

Important: In order to download spreadsheets, your client needs a valid token for the Spreadsheets API service. See downloading spreadsheets using AuthSub/OAuth and downloading spreadsheets using ClientLogin for more details.

The same idea can be applied to exporting spreadsheets. The following example fetches first spreadsheet from the user's doclist and exports the DocumentListEntry object as a .csv. Additionally, there's another helper that would take a presentations's resource ID and manually constructs the Export url.

URL feedUrl = new URL("http://docs.google.com/feeds/default/private/full/-/spreadsheet?max-results=1");
List<DocumentListEntry> entries  = client.getFeed(feedUrl, DocumentListFeed.class).getEntries();

downloadSpreadsheet(entries.get(0), "/path/to/export/to/mySpreadsheet.csv");

// OR
// downloadSpreadsheet("spreadsheet:dfrkj84g_9128gtvh8nt", "/path/to/export/to/mySpreadsheet.csv");

public void downloadSpreadsheet(String resourceId, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String docId = resourceId.substring(resourceId.lastIndexOf(":") + 1);
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = "http://spreadsheets.google.com/feeds/download/spreadsheets" +
      "/Export?key=" + docId + "&exportFormat=" + fileExtension;

  // If exporting to .csv or .tsv, add the gid parameter to specify which sheet to export
  if (fileExtension.equals("csv") || fileExtension.equals("tsv")) {
    exportUrl += "&gid=0";  // gid=0 will download only the first sheet
  }

  downloadFile(exportUrl, filepath);
}

public void downloadSpreadsheet(DocumentListEntry entry, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = ((MediaContent) entry.getContent()).getUri() + "&exportFormat=" + fileExtension;

  // If exporting to .csv or .tsv, add the gid parameter to specify which sheet to export
  if (fileExtension.equals("csv") || fileExtension.equals("tsv")) {
    exportUrl += "&gid=0";  // gid=0 will download only the first sheet
  }

  downloadFile(exportUrl, filepath);
}

Exporting Spreadsheets using AuthSub/OAuth

If you wish to use the same OAuth/AuthSub token to download spreadsheets, request a multi-scoped token good for http://docs.google.com/feeds/ and http://spreadsheets.google.com/feeds. For example, pass String scope = "http://docs.google.com/feeds/ http://spreadsheets.google.com/feeds/" to AuthSubUtil.getRequestUrl(). If you do that, the example above will work as is.

Exporting Spreadsheets using ClientLogin

For ClientLogin, the process is somewhat more involved. First create a SpreadsheetsService object (to obtain a spreadsheets token), and then swap that token into your DocsService object. This example demonstrates that process:

import com.google.gdata.client.spreadsheet.SpreadsheetService;

// Authenticate against the Spreadsheets API to obtain an auth token
SpreadsheetService spread_client = new SpreadsheetService("yourCo-yourAppName-v1");
spread_client.setUserCredentials("example@gmail.com", "pa$$word");

// Substitute the spreadsheets token for the docs token
UserToken docsToken = (UserToken) client.getAuthTokenFactory().getAuthToken();
UserToken spreadsheetsToken = (UserToken) spread_client.getAuthTokenFactory().getAuthToken();
client.setUserToken(spreadsheetsToken.getValue());

downloadSpreadsheet(entry, "/path/to/export/to/spreadsheet.xls");

// Restore docs token for our DocList client
client.setUserToken(docsToken.getValue());

Downloading PDFs

Native PDF files cannot be exported in a format other than .pdf. It is also not possible to manually contruct the download URL for these types of files. Instead, send an authenticated HTTP GET to the DocumentListEntry's <content> src link:

URL feedUrl = new URL("http://docs.google.com/feeds/default/private/full/-/pdf?max-results=1");
List<DocumentListEntry> entries  = client.getFeed(feedUrl, DocumentListFeed.class).getEntries();

downloadPDF(entries.get(0), "/path/to/export/to/myPDF.pdf");

// OR
// downloadPDF("pdf:dfrkj84g_9128gtvh8nt", "/path/to/export/to/my_pdf_file.pdf");

public void downloadPDF(DocumentListEntry entry, String filepath)
    throws MalformedURLException, IOException, ServiceException {
  MediaContent mc = (MediaContent) entry.getContent();
  String fileExtension = mc.getMimeType().getSubType();
  String exportUrl = mc.getUri();

  // PDF file cannot be exported in different formats.
  String requestedExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  if (!requestedExtension.equals(fileExtension)) {
    System.err.println("Warning: " + mc.getMimeType().getMediaType() +
        " cannot be downloaded as a " + requestedExtension + ". Using ." +
        fileExtension + " instead.");
    filepath = filepath.substring(0, filepath.lastIndexOf(".") + 1) + fileExtension;
  }

  downloadFile(exportUrl, filepath);
}

public void downloadPDF(String resourceId, String filepath)
    throws MalformedURLException, IOException, ServiceException {
  // First, fetch entry using the resourceId
  URL url = new URL("http://docs.google.com/feeds/default/private/full/" + resourceId);
  DocumentListEntry entry = client.getEntry(url, DocumentListEntry.class);
  downloadPDF(entry, filepath);
}

Note: The server to use when downloading PDFs is http://docs.googleusercontent.com (as opposed to http://docs.google.com). Therefore make sure to request a multi-scoped AuthSub/OAuth token that is also valid for http://docs.googleusercontent.com. See the note in the Downloading Documents section. Nothing special needs to be done for ClientLogin.

Back to top

Folder management

Creating folders

Creating a folder is similar to creating an empty document. Use the insert method as follows:

DocumentListEntry folderEntry = createFolder("New Folder");

public DocumentListEntry createFolder(String title) throws IOException, ServiceException {
  DocumentListEntry newEntry = new FolderEntry();
  newEntry.setTitle(new PlainTextConstruct(title));
  URL feedUrl = new URL("http://docs.google.com/feeds/default/private/full/");
  return client.insert(feedUrl, newEntry);
}

Creating a subfolder

Creating a subfolder is similar to creating an empty document in a folder. Just modify the overloaded version of the createNewDocument() method (above) to accept a FolderEntry.

Moving documents/folders in and out folders

Moving a document or folder into a parent folder requires that you have a DocumentListEntry object for the source, and another for the folder in which the document should be moved to. Ultimately, a new entry is created with its Atom <id> set to the source document/folder's ID. An HTTP POST is then sent to the folder entry's content src link. Here is an example:

Moving a resource into a folder

public DocumentListEntry moveToFolder(DocumentListEntry sourceEntry, DocumentListEntry destFolderEntry)
    throws IOException, MalformedURLException, ServiceException {

  DocumentListEntry newEntry = null;

  String docType = sourceEntry.getType();
  if (docType.equals("document")) {
    newEntry = new DocumentEntry();
  } else if (docType.equals("presentation")) {
    newEntry = new PresentationEntry();
  } else if (docType.equals("spreadsheet")) {
    newEntry = new SpreadsheetEntry();
  } else if (docType.equals("folder")) {
    newEntry = new FolderEntry();
  } else if (docType.equals("pdf")) {
    newEntry = new PdfEntry();
  } else {
    newEntry = new DocumentListEntry(); // Unknown type
  }
  newEntry.setId(sourceEntry.getId());

  String destFolderUri = ((MediaContent) destFolderEntry.getContent()).getUri();

  return client.insert(new URL(destFolderUri), newEntry);
}

Moving a resource out of a folder

Moving a folder or document out of its parent folder can be done be executing a delete() on the source folder entry's edit link and appending the document's resource ID. It is assumed that documentEntry and parentFolderEntry are DocumentListEntry objects representing the source entry (i.e. the one to be removed from the folder) and the folder to remove the document from, respectively.

moveOutOfFolder(documentEntry, parentFolderEntry);

public void moveOutOfFolder(DocumentListEntry sourceEntry, DocumentListEntry parentFolderEntry)
    throws IOException, MalformedURLException, ServiceException {
  String folderContentUri = ((MediaContent) parentFolderEntry.getContent()).getUri();
  client.delete(new URL(folderContentUri + "/" + sourceEntry.getResourceId()), sourceEntry.getEtag());
}

Back to top

Modifying Document and Folder Sharing Permissions

Retrieving the ACL feed

To retrieve the ACL permissions for a document or folder, you need the entry's <gd:feedLink> from the Atom entry. The DocumentListEntry has a getAclFeedLink() method for finding this value.

The following example fetches the first document the authenticated user owns, queries its ACL feed, and prints out the permission entries:

DocumentQuery query = new DocumentQuery(new URL("http://docs.google.com/feeds/default/private/full/-/mine"));
DocumentListFeed resultFeed = client.getFeed(query, DocumentListFeed.class);
DocumentListEntry entry = resultFeed.getEntries().get(0);

AclFeed aclFeed = client.getFeed(new URL(entry.getAclFeedLink().getHref()), AclFeed.class);
for (AclEntry entry : aclFeed.getEntries()) {
  System.out.println(
      entry.getScope().getValue() + " (" + entry.getScope().getType() + ") : " + entry.getRole().getValue());
}

Modifying the ACL feed for a document

Adding a new permission

To add a new permission to a document or folder, your client needs to create a new AclEntry and POST it to the server.

Here's an example that adds 'user@example.com' as a reader to the document/folder represented by entry, a DocumentListEntry object:

AclRole role = new AclRole("reader");
AclScope scope = new AclScope(AclScope.Type.USER, "user@example.com");
AclEntry aclEntry = addAclRole(role, scope, entry);

public AclEntry addAclRole(AclRole role, AclScope scope, DocumentListEntry entry)
    throws IOException, MalformedURLException, ServiceException  {
  AclEntry aclEntry = new AclEntry();
  aclEntry.setRole(role);
  aclEntry.setScope(scope);

  return client.insert(new URL(entry.getAclFeedLink().getHref()), aclEntry);
}

Possible values for the AclRole are reader, writer, and owner.

Group and Domain level sharing

Similar to sharing with a single user, you can share documents or folders across a Group or domain if you have a Google Apps domain.

To share a document or folder with an entire Google Apps domain, set the AclScope as such:

AclScope scope = new AclScope(AclScope.Type.DOMAIN, "example.com");

Note: Certain sharing ACLs may only be possible if the domain is configured to allow such permissions (e.g. if sharing outside of the domain for Google Apps domains is enabled, etc).

To share a document or folder with a Google Group mailing list, set the AclScope as such:

AclScope scope = new AclScope(AclScope.Type.GROUP, "mailing_list@example.com");

Updating sharing permissions

You can update an existing ACL permission by sending a PUT request (with the updated content payload) to the edit link of the acl entry in question.

This example modifies the previous aclEntry by updating 'user@example.com' to be a writer (collaborator):

aclEntry.setRole(new AclRole("writer"));
AclEntry updatedAclEntry = aclEntry.update();

// Could also use the client's update method
// client.update(new URL(aclEntry.getEditLink().getHref()), aclEntry);

Removing sharing permissions

Deleting a permission invovles sending a DELETE to the ACL entry's edit link.

aclEntry.delete();

// Could also use the client's delete method
// client.delete(new URL(aclEntry.getEditLink().getHref()), aclEntry);

Back to top

Document Revisions

Retrieving document revisions

Document revisions are available via the RevisionFeed and RevisionEntry classes. Similar to an <gd:feedLink> for ACLs, document entries will have a <gd:feedLink> pointing to the revisions feed. To fetch the revision history for a document, send an HTTP GET to the revision feed. This example fetches the revision history for the DocumentListEntry object in entry and prints some information about that feed:

RevisionFeed revisionFeed = getRevisionsFeed(entry);

// OR
// RevisionFeed revisionFeed = getRevisionsFeed("document:12345");

for (RevisionEntry entry : revisionFeed.getEntries()) {
  printRevisionEntry(entry);
}

public RevisionFeed getRevisionsFeed(String resourceId) throws IOException,
    MalformedURLException, ServiceException {
  URL url = new URL("http://docs.google.com/feeds/default/private/full/" + resourceId + "/revisions");
  return client.getFeed(url, RevisionFeed.class);
}

public RevisionFeed getRevisionsFeed(DocumentListEntry entry) throws IOException,
    MalformedURLException, ServiceException {
  URL url = new URL(entry.getSelfLink().getHref() + "/revisions");
  return client.getFeed(url, RevisionFeed.class);
}

public void printRevisionEntry(RevisionEntry entry) {
  StringBuffer output = new StringBuffer();

  output.append(" -- " + entry.getTitle().getPlainText());
  output.append(", created on " + entry.getUpdated().toUiString() + " ");
  output.append(" by " + entry.getModifyingUser().getName() + " - "
      + entry.getModifyingUser().getEmail() + "\n");
  output.append("    " + entry.getHtmlLink().getHref());

  System.out.println(output);
}

Properties of a RevisionEntry:

  • The RevisionEntry.getUpdated() is the timestamp a revision was created.
  • The RevisionEntry.getModifyingUser() is the creator of that revision.

Note: While document and presentation revisions have an autoincrementing revision number, this may have gaps if revisions are deleted so you should not rely on a sequencial sequence. Spreadsheet revisions look almost identical, but their revision ids are not zero based and auto-incrementing - instead they are based on the revision's timestamp, and so they will be an increasing series of random-looking numbers

Downloading a revision

Similar to downloading documents, you can download a individual revision and specify and exportFormat. This example assumes you have already have the RevisionEntry object as revisionEntry. It also reuses the downloadFile() helper (from above).

downloadRevision(revisionEntry, "/path/to/export/to/myDocument.pdf");

public void downloadRevision(RevisionEntry entry, String filepath)
    throws IOException, MalformedURLException, ServiceException {
  String fileExtension = filepath.substring(filepath.lastIndexOf(".") + 1);
  String exportUrl = ((OutOfLineContent) entry.getContent()).getUri() + "&exportFormat=" + fileExtension;
  downloadFile(exportUrl, filepath);
}

Note: You will need a valid AuthSub/OAuth or ClientLogin token valid for the appropriate service. See downloading documents.

Back to top