PageRenderTime 73ms CodeModel.GetById 16ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/src/DocumentList.java

http://google-docs-upload.googlecode.com/
Java | 1060 lines | 527 code | 126 blank | 407 comment | 198 complexity | 0e001081c0585c2a561bac3443733afc MD5 | raw file
   1/* Copyright (c) 2008 Google Inc.
   2 *
   3 * Licensed under the Apache License, Version 2.0 (the "License");
   4 * you may not use this file except in compliance with the License.
   5 * You may obtain a copy of the License at
   6 *
   7 *     http://www.apache.org/licenses/LICENSE-2.0
   8 *
   9 * Unless required by applicable law or agreed to in writing, software
  10 * distributed under the License is distributed on an "AS IS" BASIS,
  11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 * See the License for the specific language governing permissions and
  13 * limitations under the License.
  14 */
  15
  16import java.io.File;
  17import java.io.FileOutputStream;
  18import java.io.IOException;
  19import java.io.InputStream;
  20import java.net.MalformedURLException;
  21import java.net.URL;
  22import java.util.HashMap;
  23import java.util.Iterator;
  24import java.util.Map;
  25import java.util.Set;
  26
  27import javax.activation.MimetypesFileTypeMap;
  28
  29import com.google.gdata.client.DocumentQuery;
  30import com.google.gdata.client.GoogleService;
  31import com.google.gdata.client.Query;
  32import com.google.gdata.client.GoogleAuthTokenFactory.UserToken;
  33import com.google.gdata.client.docs.DocsService;
  34import com.google.gdata.data.Link;
  35import com.google.gdata.data.MediaContent;
  36import com.google.gdata.data.PlainTextConstruct;
  37import com.google.gdata.data.acl.AclEntry;
  38import com.google.gdata.data.acl.AclFeed;
  39import com.google.gdata.data.acl.AclRole;
  40import com.google.gdata.data.acl.AclScope;
  41import com.google.gdata.data.docs.DocumentEntry;
  42import com.google.gdata.data.docs.DocumentListEntry;
  43import com.google.gdata.data.docs.DocumentListFeed;
  44import com.google.gdata.data.docs.FolderEntry;
  45import com.google.gdata.data.docs.PresentationEntry;
  46import com.google.gdata.data.docs.RevisionFeed;
  47import com.google.gdata.data.docs.SpreadsheetEntry;
  48import com.google.gdata.data.media.MediaSource;
  49import com.google.gdata.util.AuthenticationException;
  50import com.google.gdata.util.ServiceException;
  51
  52/**
  53 * An application that serves as a sample to show how the GoogleDocsUpload List
  54 * Service can be used to search your documents, upload and download files,
  55 * change sharing permission, file documents in folders, and view revisions
  56 * history.
  57 */
  58public class DocumentList {
  59	public DocsService service;
  60	public GoogleService spreadsheetsService;
  61
  62	public static final String DEFAULT_AUTH_PROTOCOL = "https";
  63	public static final String DEFAULT_AUTH_HOST = "docs.google.com";
  64
  65	public static final String DEFAULT_PROTOCOL = "http";
  66	public static final String DEFAULT_HOST = "docs.google.com";
  67
  68	public static final String SPREADSHEETS_SERVICE_NAME = "wise";
  69	public static final String SPREADSHEETS_HOST = "spreadsheets.google.com";
  70
  71	private final String URL_FEED = "/feeds";
  72	private final String URL_DOWNLOAD = "/download";
  73	private final String URL_DOCLIST_FEED = "/private/full";
  74
  75	private final String URL_DEFAULT = "/default";
  76	private final String URL_FOLDERS = "/contents";
  77	private final String URL_ACL = "/acl";
  78	private final String URL_REVISIONS = "/revisions";
  79
  80	private final String URL_CATEGORY_DOCUMENT = "/-/document";
  81	private final String URL_CATEGORY_SPREADSHEET = "/-/spreadsheet";
  82	private final String URL_CATEGORY_PDF = "/-/pdf";
  83	private final String URL_CATEGORY_PRESENTATION = "/-/presentation";
  84	private final String URL_CATEGORY_STARRED = "/-/starred";
  85	private final String URL_CATEGORY_TRASHED = "/-/trashed";
  86	private final String URL_CATEGORY_FOLDER = "/-/folder";
  87	private final String URL_CATEGORY_EXPORT = "/Export";
  88
  89	private final String PARAMETER_SHOW_FOLDERS = "showfolders=true";
  90
  91	@SuppressWarnings("unused")
  92	private String applicationName;
  93	@SuppressWarnings("unused")
  94	private String authProtocol;
  95	@SuppressWarnings("unused")
  96	private String authHost;
  97	private String protocol;
  98	private String host;
  99	@SuppressWarnings("unused")
 100	private String username;
 101	@SuppressWarnings("unused")	
 102	private String password;
 103	@SuppressWarnings("unused")
 104	private String authSubToken;
 105
 106	private final Map<String, String> DOWNLOAD_DOCUMENT_FORMATS;
 107	{
 108		DOWNLOAD_DOCUMENT_FORMATS = new HashMap<String, String>();
 109		DOWNLOAD_DOCUMENT_FORMATS.put("doc", "doc");
 110		DOWNLOAD_DOCUMENT_FORMATS.put("txt", "txt");
 111		DOWNLOAD_DOCUMENT_FORMATS.put("odt", "odt");
 112		DOWNLOAD_DOCUMENT_FORMATS.put("pdf", "pdf");
 113		DOWNLOAD_DOCUMENT_FORMATS.put("png", "png");
 114		DOWNLOAD_DOCUMENT_FORMATS.put("rtf", "rtf");
 115		DOWNLOAD_DOCUMENT_FORMATS.put("html", "html");
 116		DOWNLOAD_DOCUMENT_FORMATS.put("zip", "zip");
 117	}
 118
 119	private final Map<String, String> DOWNLOAD_PRESENTATION_FORMATS;
 120	{
 121		DOWNLOAD_PRESENTATION_FORMATS = new HashMap<String, String>();
 122		DOWNLOAD_PRESENTATION_FORMATS.put("pdf", "pdf");
 123		DOWNLOAD_PRESENTATION_FORMATS.put("png", "png");
 124		DOWNLOAD_PRESENTATION_FORMATS.put("ppt", "ppt");
 125		DOWNLOAD_PRESENTATION_FORMATS.put("swf", "swf");
 126		DOWNLOAD_PRESENTATION_FORMATS.put("txt", "txt");
 127	}
 128
 129	private final Map<String, String> DOWNLOAD_SPREADSHEET_FORMATS;
 130	{
 131		DOWNLOAD_SPREADSHEET_FORMATS = new HashMap<String, String>();
 132		DOWNLOAD_SPREADSHEET_FORMATS.put("xls", "xls");
 133		DOWNLOAD_SPREADSHEET_FORMATS.put("ods", "ods");
 134		DOWNLOAD_SPREADSHEET_FORMATS.put("pdf", "pdf");
 135		DOWNLOAD_SPREADSHEET_FORMATS.put("csv", "csv");
 136		DOWNLOAD_SPREADSHEET_FORMATS.put("tsv", "tsv");
 137		DOWNLOAD_SPREADSHEET_FORMATS.put("html", "html");
 138	}
 139
 140	/**
 141	 * Constructor.
 142	 *
 143	 * @param applicationName name of the application.
 144	 * @throws DocumentListException the document list exception
 145	 */
 146	public DocumentList(String applicationName) throws DocumentListException {
 147		this(applicationName, DEFAULT_AUTH_PROTOCOL, DEFAULT_AUTH_HOST, DEFAULT_PROTOCOL, DEFAULT_HOST);
 148	}
 149
 150	/**
 151	 * Constructor.
 152	 *
 153	 * @param applicationName name of the application
 154	 * @param authProtocol the protocol to use for authentication
 155	 * @param authHost the host to use for authentication
 156	 * @param protocol the protocol to use for the http calls.
 157	 * @param host the host that contains the feeds
 158	 * @throws DocumentListException the document list exception
 159	 */
 160	public DocumentList(String applicationName, String authProtocol, String authHost, String protocol, String host) throws DocumentListException {
 161		if (authProtocol == null || authHost == null || protocol == null || host == null) {
 162			throw new DocumentListException("null passed in required parameters");
 163		}
 164
 165		service = new DocsService(applicationName);
 166
 167		// Creating a spreadsheets service is necessary for downloading
 168		// spreadsheets
 169		spreadsheetsService = new GoogleService(SPREADSHEETS_SERVICE_NAME, applicationName);
 170
 171		this.applicationName = applicationName;
 172		this.authProtocol = authProtocol;
 173		this.authHost = authHost;
 174		this.protocol = protocol;
 175		this.host = host;
 176	}
 177
 178	/**
 179	 * Set user credentials based on a username and password.
 180	 *
 181	 * @param user username to log in with.
 182	 * @param pass password for the user logging in.
 183	 * @throws AuthenticationException the authentication exception
 184	 * @throws DocumentListException the document list exception
 185	 */
 186	public void login(String user, String pass) throws AuthenticationException, DocumentListException {
 187		if (user == null || pass == null) {
 188			throw new DocumentListException("null login credentials");
 189		}
 190
 191		this.username = user;
 192		this.password = pass;
 193		this.authSubToken = "";
 194		service.setUserCredentials(user, pass);
 195		spreadsheetsService.setUserCredentials(user, pass);
 196	}
 197
 198	/**
 199	 * Allow a user to login using an AuthSub token.
 200	 *
 201	 * @param token the token to be used when logging in.
 202	 * @throws AuthenticationException the authentication exception
 203	 * @throws DocumentListException the document list exception
 204	 */
 205	public void loginWithAuthSubToken(String token) throws AuthenticationException, DocumentListException {
 206		if (token == null) {
 207			throw new DocumentListException("null login credentials");
 208		}
 209
 210		this.authSubToken = token;
 211		this.username = "";
 212		this.password = "";
 213
 214		service.setAuthSubToken(token);
 215		spreadsheetsService.setAuthSubToken(token);
 216	}
 217
 218	/**
 219	 * Create a new item in the DocList.
 220	 *
 221	 * @param title the title of the document to be created.
 222	 * @param type the type of the document to be created. One of "spreadsheet",
 223	 * "presentation", or "document".
 224	 * @return the document list entry
 225	 * @throws MalformedURLException the malformed url exception
 226	 * @throws IOException Signals that an I/O exception has occurred.
 227	 * @throws ServiceException the service exception
 228	 * @throws DocumentListException the document list exception
 229	 */
 230	public DocumentListEntry createNew(String title, String type) throws MalformedURLException, IOException, ServiceException, DocumentListException {
 231		if (title == null || type == null) {
 232			throw new DocumentListException("null title or type");
 233		}
 234
 235		DocumentListEntry newEntry = null;
 236		if (type.equals("document")) {
 237			newEntry = new DocumentEntry();
 238		} else if (type.equals("presentation")) {
 239			newEntry = new PresentationEntry();
 240		} else if (type.equals("spreadsheet")) {
 241			newEntry = new SpreadsheetEntry();
 242		} else if (type.equals("folder")) {
 243			newEntry = new FolderEntry();
 244		}
 245
 246		newEntry.setTitle(new PlainTextConstruct(title));
 247		return service.insert(buildUrl(URL_DEFAULT + URL_DOCLIST_FEED), newEntry);
 248	}
 249
 250	/**
 251	 * Creates the new sub folder.
 252	 *
 253	 * @param title the title
 254	 * @param folderResourceId the folder resource id
 255	 * @return the document list entry
 256	 * @throws IOException Signals that an I/O exception has occurred.
 257	 * @throws ServiceException the service exception
 258	 * @throws DocumentListException the document list exception
 259	 */
 260	public DocumentListEntry createNewSubFolder(String title, String folderResourceId) throws IOException, ServiceException, DocumentListException {
 261		DocumentListEntry newEntry = new FolderEntry();
 262		newEntry.setTitle(new PlainTextConstruct(title));
 263		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId + URL_FOLDERS);
 264		return service.insert(url, newEntry);
 265	}
 266
 267	/**
 268	 * Gets a feed containing the documents.
 269	 * 
 270	 * @param category
 271	 *            what types of documents to list: "all": lists all the doc
 272	 *            objects (documents, spreadsheets, presentations) "folders":
 273	 *            lists all doc objects including folders. "documents": lists
 274	 *            only documents. "spreadsheets": lists only spreadsheets.
 275	 *            "pdfs": lists only pdfs. "presentations": lists only
 276	 *            presentations. "starred": lists only starred objects.
 277	 *            "trashed": lists trashed objects.
 278	 * 
 279	 * @throws IOException
 280	 * @throws MalformedURLException
 281	 * @throws ServiceException
 282	 * @throws DocumentListException
 283	 */
 284	public DocumentListFeed getDocsListFeed(String category) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 285		if (category == null) {
 286			throw new DocumentListException("null category");
 287		}
 288
 289		URL url;
 290
 291		if (category.equals("all")) {
 292			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED);
 293		} else if (category.equals("folders")) {
 294			String[] parameters = { PARAMETER_SHOW_FOLDERS };
 295			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_FOLDER, parameters);
 296		} else if (category.equals("documents")) {
 297			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_DOCUMENT);
 298		} else if (category.equals("spreadsheets")) {
 299			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_SPREADSHEET);
 300		} else if (category.equals("pdfs")) {
 301			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PDF);
 302		} else if (category.equals("presentations")) {
 303			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PRESENTATION);
 304		} else if (category.equals("starred")) {
 305			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_STARRED);
 306		} else if (category.equals("trashed")) {
 307			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_TRASHED);
 308		} else {
 309			return null;
 310		}
 311
 312		DocumentQuery query = new DocumentQuery(url);
 313		// if (!category.equals("folders")) {
 314		// query.setMaxResults(101);
 315		// }
 316
 317		return service.getFeed(query, DocumentListFeed.class);
 318	}
 319
 320	public DocumentListFeed getDocsListFeed(Link link) throws MalformedURLException, IOException, ServiceException, DocumentListException {
 321		if (link != null) {
 322			return service.getFeed(new URL(link.getHref()), DocumentListFeed.class);
 323		}
 324		return null;
 325	}
 326
 327	/**
 328	 * Gets the entry for the provided object id.
 329	 *
 330	 * @param resourceId the resource id of the object to fetch an entry for.
 331	 * @return the docs list entry
 332	 * @throws IOException Signals that an I/O exception has occurred.
 333	 * @throws MalformedURLException the malformed url exception
 334	 * @throws ServiceException the service exception
 335	 * @throws DocumentListException the document list exception
 336	 */
 337	public DocumentListEntry getDocsListEntry(String resourceId) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 338		if (resourceId == null) {
 339			throw new DocumentListException("null resourceId");
 340		}
 341		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId);
 342
 343		return service.getEntry(url, DocumentListEntry.class);
 344	}
 345
 346	/**
 347	 * Gets the feed for all the objects contained in a folder.
 348	 *
 349	 * @param folderResourceId the resource id of the folder to return the feed for the
 350	 * contents.
 351	 * @return the folder docs list feed
 352	 * @throws IOException Signals that an I/O exception has occurred.
 353	 * @throws MalformedURLException the malformed url exception
 354	 * @throws ServiceException the service exception
 355	 * @throws DocumentListException the document list exception
 356	 */
 357	public DocumentListFeed getFolderDocsListFeed(String folderResourceId) throws IOException, MalformedURLException, ServiceException,
 358			DocumentListException {
 359		if (folderResourceId == null) {
 360			throw new DocumentListException("null folderResourceId");
 361		}
 362		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId + URL_FOLDERS);
 363		return service.getFeed(url, DocumentListFeed.class);
 364	}
 365
 366	/**
 367	 * Gets the feed for all the folders contained in a folder.
 368	 *
 369	 * @param folderResourceId the resource id of the folder to return the feed for the
 370	 * contents.
 371	 * @return the sub folders
 372	 * @throws IOException Signals that an I/O exception has occurred.
 373	 * @throws MalformedURLException the malformed url exception
 374	 * @throws ServiceException the service exception
 375	 * @throws DocumentListException the document list exception
 376	 */
 377	public DocumentListFeed getSubFolders(String folderResourceId) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 378		if (folderResourceId == null) {
 379			throw new DocumentListException("null folderResourceId");
 380		}
 381		String[] parameters = { PARAMETER_SHOW_FOLDERS };
 382		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId + URL_FOLDERS + URL_CATEGORY_FOLDER, parameters);
 383		return service.getFeed(url, DocumentListFeed.class);
 384	}
 385
 386	/**
 387	 * Gets a feed containing the documents.
 388	 *
 389	 * @param resourceId the resource id of the object to fetch revisions for.
 390	 * @return the revisions feed
 391	 * @throws IOException Signals that an I/O exception has occurred.
 392	 * @throws MalformedURLException the malformed url exception
 393	 * @throws ServiceException the service exception
 394	 * @throws DocumentListException the document list exception
 395	 */
 396	public RevisionFeed getRevisionsFeed(String resourceId) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 397		if (resourceId == null) {
 398			throw new DocumentListException("null resourceId");
 399		}
 400
 401		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_REVISIONS);
 402
 403		return service.getFeed(url, RevisionFeed.class);
 404	}
 405
 406	/**
 407	 * Search the documents, and return a feed of docs that match.
 408	 *
 409	 * @param searchParameters parameters to be used in searching criteria.
 410	 * @return the document list feed
 411	 * @throws IOException Signals that an I/O exception has occurred.
 412	 * @throws MalformedURLException the malformed url exception
 413	 * @throws ServiceException the service exception
 414	 * @throws DocumentListException the document list exception
 415	 */
 416	public DocumentListFeed search(Map<String, String> searchParameters) throws IOException, MalformedURLException, ServiceException,
 417			DocumentListException {
 418		return search(searchParameters, null);
 419	}
 420
 421	/**
 422	 * Search the documents, and return a feed of docs that match.
 423	 * 
 424	 * @param searchParameters
 425	 *            parameters to be used in searching criteria. accepted
 426	 *            parameters are: "q": Typical search query "alt": "author":
 427	 *            "updated-min": Lower bound on the last time a document'
 428	 *            content was changed. "updated-max": Upper bound on the last
 429	 *            time a document' content was changed. "edited-min": Lower
 430	 *            bound on the last time a document was edited by the current
 431	 *            user. This value corresponds to the app:edited value in the
 432	 *            Atom entry, which represents changes to the document's content
 433	 *            or metadata. "edited-max": Upper bound on the last time a
 434	 *            document was edited by the current user. This value
 435	 *            corresponds to the app:edited value in the Atom entry, which
 436	 *            represents changes to the document's content or metadata.
 437	 *            "title": Specifies the search terms for the title of a
 438	 *            document. This parameter used without title-exact will only
 439	 *            submit partial queries, not exact queries. "title-exact":
 440	 *            Specifies whether the title query should be taken as an exact
 441	 *            string. Meaningless without title. Possible values are true
 442	 *            and false. "opened-min": Bounds on the last time a document
 443	 *            was opened by the current user. Use the RFC 3339 timestamp
 444	 *            format. For example: 2005-08-09T10:57:00-08:00 "opened-max":
 445	 *            Bounds on the last time a document was opened by the current
 446	 *            user. Use the RFC 3339 timestamp format. For example:
 447	 *            2005-08-09T10:57:00-08:00 "owner": Searches for documents with
 448	 *            a specific owner. Use the email address of the owner.
 449	 *            "writer": Searches for documents which can be written to by
 450	 *            specific users. Use a single email address or a comma
 451	 *            separated list of email addresses. "reader": Searches for
 452	 *            documents which can be read by specific users. Use a single
 453	 *            email address or a comma separated list of email addresses.
 454	 *            "showfolders": Specifies whether the query should return
 455	 *            folders as well as documents. Possible values are true and
 456	 *            false.
 457	 * @param category
 458	 *            define the category to search. (documents, spreadsheets,
 459	 *            presentations, starred, trashed, folders)
 460	 * 
 461	 * @throws IOException
 462	 * @throws MalformedURLException
 463	 * @throws ServiceException
 464	 * @throws DocumentListException
 465	 */
 466	public DocumentListFeed search(Map<String, String> searchParameters, String category) throws IOException, MalformedURLException,
 467			ServiceException, DocumentListException {
 468		if (searchParameters == null) {
 469			throw new DocumentListException("searchParameters null");
 470		}
 471
 472		URL url;
 473
 474		if (category == null || category.equals("")) {
 475			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED);
 476		} else if (category.equals("documents")) {
 477			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_DOCUMENT);
 478		} else if (category.equals("spreadsheets")) {
 479			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_SPREADSHEET);
 480		} else if (category.equals("presentations")) {
 481			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_PRESENTATION);
 482		} else if (category.equals("starred")) {
 483			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_STARRED);
 484		} else if (category.equals("trashed")) {
 485			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_TRASHED);
 486		} else if (category.equals("folders")) {
 487			url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + URL_CATEGORY_FOLDER);
 488		} else {
 489			throw new DocumentListException("invaild category");
 490		}
 491
 492		Query qry = new Query(url);
 493
 494		for (String key : searchParameters.keySet()) {
 495			qry.setStringCustomParameter(key, searchParameters.get(key));
 496		}
 497
 498		return service.query(qry, DocumentListFeed.class);
 499	}
 500
 501	/**
 502	 * Upload a file.
 503	 *
 504	 * @param filepath path to uploaded file.
 505	 * @param title title to use for uploaded file.
 506	 * @param convert the convert
 507	 * @param hidden the hidden
 508	 * @return the document list entry
 509	 * @throws IOException when an error occurs in communication with the Doclist
 510	 * service.
 511	 * @throws ServiceException when the request causes an error in the Doclist service.
 512	 * @throws DocumentListException the document list exception
 513	 */
 514	public DocumentListEntry uploadFile(String filepath, String title, boolean convert, boolean hidden) throws IOException, ServiceException,
 515			DocumentListException {
 516		if (filepath == null || title == null) {
 517			throw new DocumentListException("null passed in for required parameters");
 518		}
 519
 520		File file = new File(filepath);
 521
 522		DocumentEntry newDocument = new DocumentEntry();
 523		
 524		newDocument.setFile(file, getMimeType(file));
 525		
 526		newDocument.setTitle(new PlainTextConstruct(title));
 527		newDocument.setHidden(hidden);
 528
 529		String url = URL_DEFAULT + URL_DOCLIST_FEED;
 530		if (!convert) {
 531			url += "?convert=false";
 532		}
 533		return service.insert(buildUrl(url), newDocument);
 534	}
 535
 536	/**
 537	 * Upload a file to a folder.
 538	 *
 539	 * @param filepath path to uploaded file.
 540	 * @param title title to use for uploaded file.
 541	 * @param folderResourceId the folder resource id
 542	 * @param convert the convert
 543	 * @param hidden the hidden
 544	 * @return the document list entry
 545	 * @throws IOException when an error occurs in communication with the Doclist
 546	 * service.
 547	 * @throws ServiceException when the request causes an error in the Doclist service.
 548	 * @throws DocumentListException the document list exception
 549	 */
 550	public DocumentListEntry uploadFileToFolder(String filepath, String title, String folderResourceId, boolean convert, boolean hidden)
 551			throws IOException, ServiceException, DocumentListException {
 552		if (filepath == null || title == null) {
 553			throw new DocumentListException("null passed in for required parameters");
 554		}
 555
 556		File file = new File(filepath);
 557
 558		DocumentEntry newDocument = new DocumentEntry();
 559		
 560        newDocument.setFile(file, getMimeType(file));
 561
 562		newDocument.setTitle(new PlainTextConstruct(title));
 563		newDocument.setHidden(hidden);
 564
 565		String url = URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId + URL_FOLDERS;
 566		if (!convert) {
 567			url += "?convert=false";
 568		}
 569
 570		return service.insert(buildUrl(url), newDocument);
 571	}
 572
 573	public DocumentListEntry updateFile(String filepath, String title, DocumentListEntry entry, boolean hidden) throws IOException, ServiceException,
 574			DocumentListException {
 575		if (filepath == null || title == null) {
 576			throw new DocumentListException("null passed in for required parameters");
 577		}
 578
 579		File file = new File(filepath);
 580
 581        entry.setFile(file, getMimeType(file));
 582        
 583		entry.setHidden(hidden);
 584		return entry.updateMedia(true);
 585	}
 586	
 587	public String getMimeType(File file) {
 588		String mimeType = "";
 589        try {
 590        	mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
 591        } catch (IllegalArgumentException e) {
 592        }
 593
 594        if (mimeType == "") {
 595        	mimeType = new MimetypesFileTypeMap().getContentType(file);
 596        }
 597        
 598        return mimeType;		
 599	}
 600
 601	/**
 602	 * Trash an object.
 603	 *
 604	 * @param resourceId the resource id of object to be trashed.
 605	 * @param delete true to delete the permanently, false to move it to the trash.
 606	 * @throws IOException Signals that an I/O exception has occurred.
 607	 * @throws MalformedURLException the malformed url exception
 608	 * @throws ServiceException the service exception
 609	 * @throws DocumentListException the document list exception
 610	 */
 611	public void trashObject(String resourceId, boolean delete) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 612		if (resourceId == null) {
 613			throw new DocumentListException("null resourceId");
 614		}
 615
 616		String feedUrl = URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId;
 617		if (delete) {
 618			feedUrl += "?delete=true";
 619		}
 620
 621		service.delete(buildUrl(feedUrl), getDocsListEntry(resourceId).getEtag());
 622	}
 623
 624	/**
 625	 * Remove an object from a folder.
 626	 *
 627	 * @param resourceId the resource id of an object to be removed from the folder.
 628	 * @param folderResourceId the resource id of the folder to remove the object from.
 629	 * @throws IOException Signals that an I/O exception has occurred.
 630	 * @throws MalformedURLException the malformed url exception
 631	 * @throws ServiceException the service exception
 632	 * @throws DocumentListException the document list exception
 633	 */
 634	public void removeFromFolder(String resourceId, String folderResourceId) throws IOException, MalformedURLException, ServiceException,
 635			DocumentListException {
 636		if (resourceId == null || folderResourceId == null) {
 637			throw new DocumentListException("null passed in for required parameters");
 638		}
 639
 640		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderResourceId + URL_FOLDERS + "/" + resourceId);
 641		service.delete(url, getDocsListEntry(resourceId).getEtag());
 642	}
 643
 644	/**
 645	 * Downloads a file.
 646	 *
 647	 * @param exportUrl the full url of the export link to download the file from.
 648	 * @param filepath path and name of the object to be saved as.
 649	 * @throws IOException Signals that an I/O exception has occurred.
 650	 * @throws MalformedURLException the malformed url exception
 651	 * @throws ServiceException the service exception
 652	 * @throws DocumentListException the document list exception
 653	 */
 654	public void downloadFile(URL exportUrl, String filepath) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 655		if (exportUrl == null || filepath == null) {
 656			throw new DocumentListException("null passed in for required parameters");
 657		}
 658
 659		MediaContent mc = new MediaContent();
 660		mc.setUri(exportUrl.toString());
 661		MediaSource ms = service.getMedia(mc);
 662
 663		InputStream inStream = null;
 664		FileOutputStream outStream = null;
 665
 666		try {
 667			inStream = ms.getInputStream();
 668			outStream = new FileOutputStream(filepath);
 669
 670			int c;
 671			while ((c = inStream.read()) != -1) {
 672				outStream.write(c);
 673			}
 674		} finally {
 675			if (inStream != null) {
 676				inStream.close();
 677			}
 678			if (outStream != null) {
 679				outStream.flush();
 680				outStream.close();
 681			}
 682		}
 683	}
 684
 685	/**
 686	 * Downloads a spreadsheet file.
 687	 *
 688	 * @param resourceId the resource id of the object to be downloaded.
 689	 * @param filepath path and name of the object to be saved as.
 690	 * @param format format to download the file to. The following file types are
 691	 * supported: spreadsheets: "ods", "pdf", "xls", "csv", "html",
 692	 * "tsv"
 693	 * @throws IOException Signals that an I/O exception has occurred.
 694	 * @throws MalformedURLException the malformed url exception
 695	 * @throws ServiceException the service exception
 696	 * @throws DocumentListException the document list exception
 697	 */
 698	public void downloadSpreadsheet(String resourceId, String filepath, String format) throws IOException, MalformedURLException, ServiceException,
 699			DocumentListException {
 700		if (resourceId == null || filepath == null || format == null) {
 701			throw new DocumentListException("null passed in for required parameters");
 702		}
 703
 704		UserToken docsToken = (UserToken) service.getAuthTokenFactory().getAuthToken();
 705		UserToken spreadsheetsToken = (UserToken) spreadsheetsService.getAuthTokenFactory().getAuthToken();
 706		service.setUserToken(spreadsheetsToken.getValue());
 707
 708		HashMap<String, String> parameters = new HashMap<String, String>();
 709		parameters.put("key", resourceId.substring(resourceId.lastIndexOf(':') + 1));
 710		parameters.put("exportFormat", format);
 711
 712		// If exporting to .csv or .tsv, add the gid parameter to specify which
 713		// sheet to export
 714		if (format.equals(DOWNLOAD_SPREADSHEET_FORMATS.get("csv")) || format.equals(DOWNLOAD_SPREADSHEET_FORMATS.get("tsv"))) {
 715			parameters.put("gid", "0"); // download only the first sheet
 716		}
 717
 718		URL url = buildUrl(SPREADSHEETS_HOST, URL_DOWNLOAD + "/spreadsheets" + URL_CATEGORY_EXPORT, parameters);
 719
 720		downloadFile(url, filepath);
 721
 722		// Restore docs token for our DocList client
 723		service.setUserToken(docsToken.getValue());
 724	}
 725
 726	/**
 727	 * Downloads a document.
 728	 *
 729	 * @param resourceId the resource id of the object to be downloaded.
 730	 * @param filepath path and name of the object to be saved as.
 731	 * @param format format to download the file to. The following file types are
 732	 * supported: documents: "doc", "txt", "odt", "png", "pdf",
 733	 * "rtf", "html"
 734	 * @throws IOException Signals that an I/O exception has occurred.
 735	 * @throws MalformedURLException the malformed url exception
 736	 * @throws ServiceException the service exception
 737	 * @throws DocumentListException the document list exception
 738	 */
 739	public void downloadDocument(String resourceId, String filepath, String format) throws IOException, MalformedURLException, ServiceException,
 740			DocumentListException {
 741		if (resourceId == null || filepath == null || format == null) {
 742			throw new DocumentListException("null passed in for required parameters");
 743		}
 744		String[] parameters = { "docID=" + resourceId, "exportFormat=" + format };
 745		URL url = buildUrl(URL_DOWNLOAD + "/documents" + URL_CATEGORY_EXPORT, parameters);
 746
 747		downloadFile(url, filepath);
 748	}
 749
 750	/**
 751	 * Downloads a presentation.
 752	 *
 753	 * @param resourceId the resource id of the object to be downloaded.
 754	 * @param filepath path and name of the object to be saved as.
 755	 * @param format format to download the file to. The following file types are
 756	 * supported: presentations: "pdf", "ppt", "png", "swf", "txt"
 757	 * @throws IOException Signals that an I/O exception has occurred.
 758	 * @throws MalformedURLException the malformed url exception
 759	 * @throws ServiceException the service exception
 760	 * @throws DocumentListException the document list exception
 761	 */
 762	public void downloadPresentation(String resourceId, String filepath, String format) throws IOException, MalformedURLException, ServiceException,
 763			DocumentListException {
 764		if (resourceId == null || filepath == null || format == null) {
 765			throw new DocumentListException("null passed in for required parameters");
 766		}
 767
 768		String[] parameters = { "docID=" + resourceId, "exportFormat=" + format };
 769		URL url = buildUrl(URL_DOWNLOAD + "/presentations" + URL_CATEGORY_EXPORT, parameters);
 770
 771		downloadFile(url, filepath);
 772	}
 773
 774	/**
 775	 * Moves a object to a folder.
 776	 *
 777	 * @param resourceId the resource id of the object to be moved to the folder.
 778	 * @param folderId the id of the folder to move the object to.
 779	 * @return the document list entry
 780	 * @throws IOException Signals that an I/O exception has occurred.
 781	 * @throws MalformedURLException the malformed url exception
 782	 * @throws ServiceException the service exception
 783	 * @throws DocumentListException the document list exception
 784	 */
 785	public DocumentListEntry moveObjectToFolder(String resourceId, String folderId) throws IOException, MalformedURLException, ServiceException,
 786			DocumentListException {
 787		if (resourceId == null || folderId == null) {
 788			throw new DocumentListException("null passed in for required parameters");
 789		}
 790
 791		DocumentListEntry doc = new DocumentListEntry();
 792		doc.setId(buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId).toString());
 793
 794		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + folderId + URL_FOLDERS);
 795		return service.insert(url, doc);
 796	}
 797
 798	/**
 799	 * Gets the access control list for a object.
 800	 *
 801	 * @param resourceId the resource id of the object to retrieve the ACL for.
 802	 * @return the acl feed
 803	 * @throws IOException Signals that an I/O exception has occurred.
 804	 * @throws MalformedURLException the malformed url exception
 805	 * @throws ServiceException the service exception
 806	 * @throws DocumentListException the document list exception
 807	 */
 808	public AclFeed getAclFeed(String resourceId) throws IOException, MalformedURLException, ServiceException, DocumentListException {
 809		if (resourceId == null) {
 810			throw new DocumentListException("null resourceId");
 811		}
 812
 813		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_ACL);
 814
 815		return service.getFeed(url, AclFeed.class);
 816	}
 817
 818	/**
 819	 * Add an ACL role to an object.
 820	 *
 821	 * @param role the role of the ACL to be added to the object.
 822	 * @param scope the scope for the ACL.
 823	 * @param resourceId the resource id of the object to set the ACL for.
 824	 * @return the acl entry
 825	 * @throws IOException Signals that an I/O exception has occurred.
 826	 * @throws MalformedURLException the malformed url exception
 827	 * @throws ServiceException the service exception
 828	 * @throws DocumentListException the document list exception
 829	 */
 830	public AclEntry addAclRole(AclRole role, AclScope scope, String resourceId) throws IOException, MalformedURLException, ServiceException,
 831			DocumentListException {
 832		if (role == null || scope == null || resourceId == null) {
 833			throw new DocumentListException("null passed in for required parameters");
 834		}
 835
 836		AclEntry entry = new AclEntry();
 837		entry.setRole(role);
 838		entry.setScope(scope);
 839		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_ACL);
 840
 841		return service.insert(url, entry);
 842	}
 843
 844	/**
 845	 * Change the ACL role of a file.
 846	 *
 847	 * @param role the new role of the ACL to be updated.
 848	 * @param scope the new scope for the ACL.
 849	 * @param resourceId the resource id of the object to be updated.
 850	 * @return the acl entry
 851	 * @throws IOException Signals that an I/O exception has occurred.
 852	 * @throws MalformedURLException the malformed url exception
 853	 * @throws ServiceException the service exception
 854	 * @throws DocumentListException the document list exception
 855	 */
 856	public AclEntry changeAclRole(AclRole role, AclScope scope, String resourceId) throws IOException, MalformedURLException, ServiceException,
 857			DocumentListException {
 858		if (role == null || scope == null || resourceId == null) {
 859			throw new DocumentListException("null passed in for required parameters");
 860		}
 861
 862		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_ACL);
 863
 864		return service.update(url, scope, role);
 865	}
 866
 867	/**
 868	 * Remove an ACL role from a object.
 869	 *
 870	 * @param scope scope of the ACL to be removed.
 871	 * @param email email address to remove the role of.
 872	 * @param resourceId the resource id of the object to remove the role from.
 873	 * @throws IOException Signals that an I/O exception has occurred.
 874	 * @throws MalformedURLException the malformed url exception
 875	 * @throws ServiceException the service exception
 876	 * @throws DocumentListException the document list exception
 877	 */
 878	public void removeAclRole(String scope, String email, String resourceId) throws IOException, MalformedURLException, ServiceException,
 879			DocumentListException {
 880		if (scope == null || email == null || resourceId == null) {
 881			throw new DocumentListException("null passed in for required parameters");
 882		}
 883
 884		URL url = buildUrl(URL_DEFAULT + URL_DOCLIST_FEED + "/" + resourceId + URL_ACL + "/" + scope + "%3A" + email);
 885
 886		service.delete(url);
 887	}
 888
 889	/**
 890	 * Returns the format code based on a file extension, and object id.
 891	 *
 892	 * @param resourceId the resource id of the object you want the format for.
 893	 * @param ext extension of the file you want the format for.
 894	 * @return the download format
 895	 * @throws DocumentListException the document list exception
 896	 */
 897	public String getDownloadFormat(String resourceId, String ext) throws DocumentListException {
 898		if (resourceId == null || ext == null) {
 899			throw new DocumentListException("null passed in for required parameters");
 900		}
 901
 902		if (resourceId.indexOf("document") == 0) {
 903			if (DOWNLOAD_DOCUMENT_FORMATS.containsKey(ext)) {
 904				return DOWNLOAD_DOCUMENT_FORMATS.get(ext);
 905			}
 906		} else if (resourceId.indexOf("presentation") == 0) {
 907			if (DOWNLOAD_PRESENTATION_FORMATS.containsKey(ext)) {
 908				return DOWNLOAD_PRESENTATION_FORMATS.get(ext);
 909			}
 910		} else if (resourceId.indexOf("spreadsheet") == 0) {
 911			if (DOWNLOAD_SPREADSHEET_FORMATS.containsKey(ext)) {
 912				return DOWNLOAD_SPREADSHEET_FORMATS.get(ext);
 913			}
 914		}
 915		throw new DocumentListException("invalid document type");
 916	}
 917
 918	/**
 919	 * Gets the suffix of the resourceId. If the resourceId is
 920	 * "document:dh3bw3j_0f7xmjhd8", "dh3bw3j_0f7xmjhd8" will be returned.
 921	 *
 922	 * @param resourceId the resource id to extract the suffix from.
 923	 * @return the resource id suffix
 924	 * @throws DocumentListException the document list exception
 925	 */
 926	public String getResourceIdSuffix(String resourceId) throws DocumentListException {
 927		if (resourceId == null) {
 928			throw new DocumentListException("null resourceId");
 929		}
 930
 931		if (resourceId.indexOf("%3A") != -1) {
 932			return resourceId.substring(resourceId.lastIndexOf("%3A") + 3);
 933		} else if (resourceId.indexOf(":") != -1) {
 934			return resourceId.substring(resourceId.lastIndexOf(":") + 1);
 935		}
 936		throw new DocumentListException("Bad resourceId");
 937	}
 938
 939	/**
 940	 * Gets the prefix of the resourceId. If the resourceId is
 941	 * "document:dh3bw3j_0f7xmjhd8", "document" will be returned.
 942	 *
 943	 * @param resourceId the resource id to extract the suffix from.
 944	 * @return the resource id prefix
 945	 * @throws DocumentListException the document list exception
 946	 */
 947	public String getResourceIdPrefix(String resourceId) throws DocumentListException {
 948		if (resourceId == null) {
 949			throw new DocumentListException("null resourceId");
 950		}
 951
 952		if (resourceId.indexOf("%3A") != -1) {
 953			return resourceId.substring(0, resourceId.indexOf("%3A"));
 954		} else if (resourceId.indexOf(":") != -1) {
 955			return resourceId.substring(0, resourceId.indexOf(":"));
 956		} else {
 957			throw new DocumentListException("Bad resourceId");
 958		}
 959	}
 960
 961	/**
 962	 * Builds a URL from a patch.
 963	 *
 964	 * @param path the path to add to the protocol/host
 965	 * @return the URL
 966	 * @throws MalformedURLException the malformed url exception
 967	 * @throws DocumentListException the document list exception
 968	 */
 969	private URL buildUrl(String path) throws MalformedURLException, DocumentListException {
 970		if (path == null) {
 971			throw new DocumentListException("null path");
 972		}
 973
 974		return buildUrl(path, null);
 975	}
 976
 977	/**
 978	 * Builds a URL with parameters.
 979	 *
 980	 * @param path the path to add to the protocol/host
 981	 * @param parameters parameters to be added to the URL.
 982	 * @return the uRL
 983	 * @throws MalformedURLException the malformed url exception
 984	 * @throws DocumentListException the document list exception
 985	 */
 986	private URL buildUrl(String path, String[] parameters) throws MalformedURLException, DocumentListException {
 987		if (path == null) {
 988			throw new DocumentListException("null path");
 989		}
 990
 991		return buildUrl(host, path, parameters);
 992	}
 993
 994	/**
 995	 * Builds a URL with parameters.
 996	 *
 997	 * @param domain the domain of the server
 998	 * @param path the path to add to the protocol/host
 999	 * @param parameters parameters to be added to the URL.
1000	 * @return the uRL
1001	 * @throws MalformedURLException the malformed url exception
1002	 * @throws DocumentListException the document list exception
1003	 */
1004	private URL buildUrl(String domain, String path, String[] parameters) throws MalformedURLException, DocumentListException {
1005		if (path == null) {
1006			throw new DocumentListException("null path");
1007		}
1008
1009		StringBuffer url = new StringBuffer();
1010		url.append(protocol + "://" + domain + URL_FEED + path);
1011
1012		if (parameters != null && parameters.length > 0) {
1013			url.append("?");
1014			for (int i = 0; i < parameters.length; i++) {
1015				url.append(parameters[i]);
1016				if (i != (parameters.length - 1)) {
1017					url.append("&");
1018				}
1019			}
1020		}
1021
1022		return new URL(url.toString());
1023	}
1024
1025	/**
1026	 * Builds a URL with parameters.
1027	 *
1028	 * @param domain the domain of the server
1029	 * @param path the path to add to the protocol/host
1030	 * @param parameters parameters to be added to the URL as key value pairs.
1031	 * @return the uRL
1032	 * @throws MalformedURLException the malformed url exception
1033	 * @throws DocumentListException the document list exception
1034	 */
1035	private URL buildUrl(String domain, String path, Map<String, String> parameters) throws MalformedURLException, DocumentListException {
1036		if (path == null) {
1037			throw new DocumentListException("null path");
1038		}
1039
1040		StringBuffer url = new StringBuffer();
1041		url.append(protocol + "://" + domain + URL_FEED + path);
1042
1043		if (parameters != null && parameters.size() > 0) {
1044			Set<Map.Entry<String, String>> params = parameters.entrySet();
1045			Iterator<Map.Entry<String, String>> itr = params.iterator();
1046
1047			url.append("?");
1048			while (itr.hasNext()) {
1049				Map.Entry<String, String> entry = itr.next();
1050				url.append(entry.getKey() + "=" + entry.getValue());
1051				if (itr.hasNext()) {
1052					url.append("&");
1053				}
1054			}
1055		}
1056
1057		return new URL(url.toString());
1058	}
1059
1060}