)
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.
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.
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.
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:
gdata-src.java.zip)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.
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.
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.
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 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
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
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
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.
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.
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() + ")"); } }
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);
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);
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);
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);
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.
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.
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.
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.
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); }
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.
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/")); }
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/")); }
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.
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.
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);
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);
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 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 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());
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();
}
}
}
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);
}
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);
}
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);
}
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.
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());
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.
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 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 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:
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 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()); }
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()); }
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.
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");
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);
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);
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:
RevisionEntry.getUpdated() is the timestamp a revision was created.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
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.