Inital commit
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
/* Copyright (c) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package sample.docs;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gdata.client.media.ResumableGDataFileUploader;
|
||||
import sample.util.SimpleCommandLineParser;
|
||||
import com.google.gdata.data.Link;
|
||||
import com.google.gdata.data.docs.DocumentListEntry;
|
||||
import com.google.gdata.data.docs.DocumentListFeed;
|
||||
import com.google.gdata.data.media.MediaFileSource;
|
||||
import com.google.gdata.util.ServiceException;
|
||||
import com.google.gdata.client.uploader.FileUploadData;
|
||||
import com.google.gdata.client.uploader.ProgressListener;
|
||||
import com.google.gdata.client.uploader.ResumableHttpFileUploader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* A console aplication to demonstrate interaction with Google Docs API to
|
||||
* upload/update large media files using Resumable Upload protocol.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DocumentResumableUploadDemo {
|
||||
|
||||
/** Default document list feed url. */
|
||||
private static final String DEFAULT_DOCLIST_FEED_URL =
|
||||
"https://docs.google.com/feeds/default/private/full";
|
||||
|
||||
/** Default create-media-url for uploading documents */
|
||||
private static final String DEFAULT_RESUMABLE_UPLOAD_URL =
|
||||
"https://docs.google.com/feeds/upload/create-session/default/private/full";
|
||||
|
||||
/** Maximum number of concurrent uploads */
|
||||
private static final int MAX_CONCURRENT_UPLOADS = 10;
|
||||
|
||||
/** Time interval at which upload task will notify about the progress */
|
||||
private static final int PROGRESS_UPDATE_INTERVAL = 1000;
|
||||
|
||||
/** Max size for each upload chunk */
|
||||
private static final int DEFAULT_CHUNK_SIZE = 10000000;
|
||||
|
||||
/**
|
||||
* Welcome message, introducing the program.
|
||||
*/
|
||||
private static final String[] WELCOME_MESSAGE = {
|
||||
"", "This is a demo of the resumable upload feature for Docs GData API",
|
||||
"Using this interface, you can upload/update large documents.", ""};
|
||||
|
||||
private static final String APPLICATION_NAME = "JavaGDataClientSampleAppV3.0";
|
||||
|
||||
private static final String[] USAGE_MESSAGE = {
|
||||
"Usage: java DocumentResumableUploadDemo.jar --username <user> --password <pass>",
|
||||
};
|
||||
|
||||
private static final String[] COMMAND_HELP_MESSAGE = {
|
||||
"Commands:",
|
||||
" list [object_type] "
|
||||
+ " [[list objects]]",
|
||||
" upload <file_path1:title1> ... <file_pathN:titleN> "
|
||||
+ "[<chunk_size_in_byes>] [[uploads set of files]]",
|
||||
" update <ducument_id> <updated_file_path> [<chunk_size_in_bytes>] "
|
||||
+ " [[updates content of an object]]",
|
||||
};
|
||||
|
||||
/** Instance of {@link DocumentList} */
|
||||
private final DocumentList docs;
|
||||
|
||||
/** Steam to print status messages to. */
|
||||
PrintStream output;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param docs {@link DocumentList} for interface to DocList API service.
|
||||
* @param out printstream to output status messages to.
|
||||
*/
|
||||
DocumentResumableUploadDemo(DocumentList docs, PrintStream out) {
|
||||
this.docs = docs;
|
||||
this.output = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out a message.
|
||||
*
|
||||
* @param msg the message to be printed.
|
||||
*/
|
||||
private static void printMessage(String[] msg) {
|
||||
for (String s : msg) {
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] parseCommand(String command) {
|
||||
return command.trim().split(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out the specified document entry.
|
||||
*
|
||||
* @param doc the document entry to print.
|
||||
*/
|
||||
public void printDocumentEntry(DocumentListEntry doc) {
|
||||
StringBuffer outputBuffer = new StringBuffer();
|
||||
|
||||
outputBuffer.append(" -- " + doc.getTitle().getPlainText() + " ");
|
||||
if (!doc.getParentLinks().isEmpty()) {
|
||||
for (Link link : doc.getParentLinks()) {
|
||||
outputBuffer.append("[" + link.getTitle() + "] ");
|
||||
}
|
||||
}
|
||||
outputBuffer.append(doc.getResourceId());
|
||||
|
||||
output.println(outputBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads given collection of files. The call blocks until all uploads are
|
||||
* done.
|
||||
*
|
||||
* @param url create-session url for initiating resumable uploads for
|
||||
* documents API.
|
||||
* @param files list of absolute filepaths to files to upload.
|
||||
* @param chunkSize max size of each upload chunk.
|
||||
*/
|
||||
public Collection<DocumentListEntry> uploadFiles(String url,
|
||||
List<String> files, int chunkSize)
|
||||
throws IOException, ServiceException, InterruptedException {
|
||||
// Create a listener
|
||||
FileUploadProgressListener listener = new FileUploadProgressListener();
|
||||
// Pool for handling concurrent upload tasks
|
||||
ExecutorService executor =
|
||||
Executors.newFixedThreadPool(MAX_CONCURRENT_UPLOADS);
|
||||
// Create {@link ResumableGDataFileUploader} for each file to upload
|
||||
List<ResumableGDataFileUploader> uploaders = Lists.newArrayList();
|
||||
for (String fileName : files) {
|
||||
MediaFileSource mediaFile = getMediaFileSource(fileName);
|
||||
ResumableGDataFileUploader uploader =
|
||||
new ResumableGDataFileUploader.Builder(
|
||||
docs.service, new URL(url), mediaFile, null /*empty meatadata*/)
|
||||
.title(mediaFile.getName())
|
||||
.chunkSize(chunkSize).executor(executor)
|
||||
.trackProgress(listener, PROGRESS_UPDATE_INTERVAL)
|
||||
.build();
|
||||
uploaders.add(uploader);
|
||||
}
|
||||
// attach the listener to list of uploaders
|
||||
listener.listenTo(uploaders);
|
||||
|
||||
// Start the upload
|
||||
for (ResumableGDataFileUploader uploader : uploaders) {
|
||||
uploader.start();
|
||||
}
|
||||
|
||||
// wait for uploads to complete
|
||||
while (!listener.isDone()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ie) {
|
||||
listener.printResults();
|
||||
throw ie; // rethrow
|
||||
}
|
||||
}
|
||||
|
||||
// print upload results
|
||||
listener.printResults();
|
||||
|
||||
// return list of uploaded entries
|
||||
return listener.getUploaded();
|
||||
}
|
||||
|
||||
private MediaFileSource getMediaFileSource(String fileName) {
|
||||
File file = new File(fileName);
|
||||
MediaFileSource mediaFile = new MediaFileSource(file,
|
||||
DocumentListEntry.MediaType.fromFileName(file.getName())
|
||||
.getMimeType());
|
||||
return mediaFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute 'list' command.
|
||||
*/
|
||||
private void executeList(String[] args) throws IOException,
|
||||
ServiceException, DocumentListException {
|
||||
DocumentListFeed feed = null;
|
||||
String msg = "";
|
||||
|
||||
switch (args.length) {
|
||||
case 1:
|
||||
msg = "List of docs: ";
|
||||
feed = docs.getDocsListFeed("all");
|
||||
break;
|
||||
case 2:
|
||||
msg = "List of all " + args[1] + ": ";
|
||||
feed = docs.getDocsListFeed(args[1]);
|
||||
break;
|
||||
case 3:
|
||||
if (args[1].equals("folder")) {
|
||||
msg = "Contents of folder_id '" + args[2] + "': ";
|
||||
feed = docs.getFolderDocsListFeed(args[2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (feed != null) {
|
||||
output.println(msg);
|
||||
for (DocumentListEntry entry : feed.getEntries()) {
|
||||
printDocumentEntry(entry);
|
||||
}
|
||||
} else {
|
||||
printMessage(COMMAND_HELP_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute 'upload' command.
|
||||
*/
|
||||
private void executeUpload(String[] args)
|
||||
throws IOException, ServiceException, InterruptedException {
|
||||
if (args.length > 1) {
|
||||
int chunkSize = DEFAULT_CHUNK_SIZE;
|
||||
List<String> files = Lists.newArrayList();
|
||||
for (int index = 1; index < args.length; index++) {
|
||||
String arg = args[index];
|
||||
if (index < args.length - 1) {
|
||||
files.add(arg);
|
||||
continue;
|
||||
}
|
||||
// Last argument can be a file or chunk size
|
||||
try {
|
||||
chunkSize = Integer.parseInt(arg);
|
||||
} catch (NumberFormatException nfe) {
|
||||
files.add(arg);
|
||||
}
|
||||
}
|
||||
uploadFiles(DEFAULT_RESUMABLE_UPLOAD_URL, files, chunkSize);
|
||||
output.println("Finished upload");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute 'update' command.
|
||||
*/
|
||||
private void executeUpdate(String[] args)
|
||||
throws IOException, ServiceException, InterruptedException {
|
||||
String docIdToUpdate = args[1];
|
||||
String filePath = args[2];
|
||||
|
||||
// retrieve latest entry
|
||||
DocumentListEntry currentEntry = docs.service.getEntry(
|
||||
new URL(DEFAULT_DOCLIST_FEED_URL + "/" + docIdToUpdate),
|
||||
DocumentListEntry.class);
|
||||
|
||||
MediaFileSource mediaFile = getMediaFileSource(filePath);
|
||||
ResumableGDataFileUploader uploader =
|
||||
new ResumableGDataFileUploader
|
||||
.Builder(docs.service, mediaFile, currentEntry)
|
||||
.title(mediaFile.getName())
|
||||
.requestType(
|
||||
ResumableGDataFileUploader.RequestType.UPDATE_MEDIA_ONLY)
|
||||
.build();
|
||||
|
||||
uploader.start();
|
||||
|
||||
// wait for upload to complete
|
||||
while (!uploader.isDone()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ie) {
|
||||
output.println("Media update interrupted at: "
|
||||
+ String.format("%3.0f", uploader.getProgress() * 100) + "%");
|
||||
throw ie; // rethrow
|
||||
}
|
||||
}
|
||||
DocumentListEntry updatedEntry =
|
||||
uploader.getResponse(DocumentListEntry.class);
|
||||
|
||||
output.println("Finished update");
|
||||
}
|
||||
|
||||
private boolean executeCommand(BufferedReader reader) throws IOException,
|
||||
ServiceException, InterruptedException {
|
||||
|
||||
output.println("Enter a command");
|
||||
|
||||
try {
|
||||
String command = reader.readLine();
|
||||
if (command == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] args = parseCommand(command);
|
||||
String name = args[0];
|
||||
|
||||
if (name.equals("list")) {
|
||||
executeList(args);
|
||||
} else if (name.equals("upload")) {
|
||||
executeUpload(args);
|
||||
} else if (name.equals("update")) {
|
||||
executeUpdate(args);
|
||||
} else if (name.startsWith("q") || name.startsWith("exit")) {
|
||||
return false;
|
||||
} else if (name.equals("help")) {
|
||||
printMessage(COMMAND_HELP_MESSAGE);
|
||||
} else {
|
||||
output.println("Unknown command. Type 'help' for list of commands");
|
||||
}
|
||||
} catch (DocumentListException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void run() throws IOException, ServiceException, InterruptedException {
|
||||
printMessage(WELCOME_MESSAGE);
|
||||
printMessage(COMMAND_HELP_MESSAGE);
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(System.in));
|
||||
|
||||
while (executeCommand(reader)) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws DocumentListException,
|
||||
IOException, ServiceException, InterruptedException {
|
||||
|
||||
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
|
||||
String user = parser.getValue("username", "user", "u");
|
||||
String password = parser.getValue("password", "pass", "p");
|
||||
boolean help = parser.containsKey("help", "h");
|
||||
|
||||
if (help || (user == null || password == null)) {
|
||||
printMessage(USAGE_MESSAGE);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// authenticate
|
||||
DocumentList docs = new DocumentList(APPLICATION_NAME);
|
||||
docs.login(user, password);
|
||||
|
||||
DocumentResumableUploadDemo demo = new DocumentResumableUploadDemo(
|
||||
docs, System.out);
|
||||
demo.run();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ProgressListener} implementation to track upload progress.
|
||||
* The listener can track multiple uploads at the same time.
|
||||
* Use {@link #isDone} to check if all uploads are completed and
|
||||
* use {@link #getUploaded} to access results of successful uploads.
|
||||
*/
|
||||
private class FileUploadProgressListener implements ProgressListener {
|
||||
|
||||
private Collection<ResumableGDataFileUploader> trackedUploaders
|
||||
= Lists.newArrayList();
|
||||
private int pendingRequests;
|
||||
Map<String, DocumentListEntry> uploaded = Maps.newHashMap();
|
||||
Map<String, String> failed = Maps.newHashMap();
|
||||
|
||||
boolean processed;
|
||||
|
||||
public FileUploadProgressListener() {
|
||||
this.pendingRequests = 0;
|
||||
}
|
||||
|
||||
public void listenTo(Collection<ResumableGDataFileUploader> uploaders) {
|
||||
this.trackedUploaders.addAll(uploaders);
|
||||
this.pendingRequests = trackedUploaders.size();
|
||||
}
|
||||
|
||||
public synchronized void progressChanged(ResumableHttpFileUploader uploader)
|
||||
{
|
||||
String fileId = ((FileUploadData) uploader.getData()).getFileName();
|
||||
switch(uploader.getUploadState()) {
|
||||
case COMPLETE:
|
||||
case CLIENT_ERROR:
|
||||
pendingRequests -= 1;
|
||||
output.println(fileId + ": Completed");
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
output.println(fileId + ":"
|
||||
+ String.format("%3.0f", uploader.getProgress() * 100) + "%");
|
||||
break;
|
||||
case NOT_STARTED:
|
||||
output.println(fileId + ":" + "Not Started");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isDone() {
|
||||
// not done if there are any pending requests.
|
||||
if (pendingRequests > 0) {
|
||||
return false;
|
||||
}
|
||||
// if all responses are processed., nothing to do.
|
||||
if (processed) {
|
||||
return true;
|
||||
}
|
||||
// check if all response streams are available.
|
||||
for (ResumableGDataFileUploader uploader : trackedUploaders) {
|
||||
if (!uploader.isDone()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// process all responses
|
||||
for (ResumableGDataFileUploader uploader : trackedUploaders) {
|
||||
String fileId = ((FileUploadData) uploader.getData()).getFileName();
|
||||
switch(uploader.getUploadState()) {
|
||||
case COMPLETE:
|
||||
try {
|
||||
DocumentListEntry entry =
|
||||
uploader.getResponse(DocumentListEntry.class);
|
||||
uploaded.put(fileId, entry);
|
||||
} catch (IOException e) {
|
||||
failed.put(fileId, "Upload completed, but unexpected error "
|
||||
+ "reading server response");
|
||||
} catch (ServiceException e) {
|
||||
failed.put(fileId,
|
||||
"Upload completed, but failed to parse server response");
|
||||
}
|
||||
break;
|
||||
case CLIENT_ERROR:
|
||||
failed.put(fileId, "Failed at " + uploader.getProgress());
|
||||
break;
|
||||
}
|
||||
}
|
||||
processed = true;
|
||||
output.println("All requests done");
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized Collection<DocumentListEntry> getUploaded() {
|
||||
if (!isDone()) {
|
||||
return null;
|
||||
}
|
||||
return uploaded.values();
|
||||
}
|
||||
|
||||
public synchronized void printResults() {
|
||||
if (!isDone()) {
|
||||
return;
|
||||
}
|
||||
output.println("Result: " + uploaded.size() + ", " + failed.size());
|
||||
if (uploaded.size() > 0) {
|
||||
output.println(" Successfully Uploaded:");
|
||||
for (Map.Entry<String, DocumentListEntry> entry : uploaded.entrySet()) {
|
||||
printDocumentEntry(entry.getValue());
|
||||
}
|
||||
}
|
||||
if (failed.size() > 0) {
|
||||
output.println(" Failed to upload:");
|
||||
for (Map.Entry entry : failed.entrySet()) {
|
||||
output.println(" " + entry.getKey() + ":" + entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out the specified document entry.
|
||||
*
|
||||
* @param doc the document entry to print.
|
||||
*/
|
||||
public void printDocumentEntry(DocumentListEntry doc) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append(" -- " + doc.getTitle().getPlainText() + " ");
|
||||
if (!doc.getParentLinks().isEmpty()) {
|
||||
for (Link link : doc.getParentLinks()) {
|
||||
buffer.append("[" + link.getTitle() + "] ");
|
||||
}
|
||||
}
|
||||
buffer.append(doc.getResourceId());
|
||||
|
||||
output.println(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user