/*
* Copyright 2014 Objectos, Fábrica de Software LTDA.
*
* 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 br.com.objectos.way.gdrive;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Changes;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.model.Change;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.common.io.CharSource;
import com.google.common.io.Resources;
/**
* @author mario.marques@objectos.com.br (Mario Marques Junior)
*/
public class GDrive {
private static final String CLIENTSECRETS_LOCATION = "/client_secrets.json";
private final Drive service;
private GDrive(Drive service) {
this.service = service;
}
public static GDrive authorize(GDriveTokens tokens) {
try {
NetHttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
URL url = Resources.getResource(GDrive.class, CLIENTSECRETS_LOCATION);
CharSource charSource = Resources.asCharSource(url, Charsets.UTF_8);
Reader reader = charSource.openStream();
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, reader);
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setClientSecrets(clientSecrets)
.build();
credential.setAccessToken(tokens.accessToken);
credential.setRefreshToken(tokens.refreshToken);
Drive drive = new Drive.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("GDrive")
.build();
return new GDrive(drive);
} catch (IOException e) {
throw new GDriveException(e);
}
}
public static GDriveTokens.Builder tokens() {
return new GDriveTokens.Builder();
}
public GDirectory root() {
try {
File file = service
.files()
.get("root")
.execute();
return new GDirectoryRoot(file, this);
} catch (IOException e) {
throw new GDriveException(e);
}
}
public GDirectory directory(String directoryId) {
try {
File file = service
.files()
.get(directoryId)
.execute();
return new GDirectoryFolder(file, this, directoryId);
} catch (IOException e) {
throw new GDriveException(e);
}
}
List<GFile> listFiles() {
return listFiles("root");
}
List<GFile> listFiles(String directoryId) {
try {
String format = new StringBuilder()
.append("'%s' in parents")
.append(" and mimeType != 'application/vnd.google-apps.folder'")
.toString();
String q = String.format(format, directoryId);
Files.List _request = service
.files()
.list()
.setQ(q);
RequestFile request = new RequestFile(_request);
Iterator<File> iterator;
iterator = new RequestIterator<File>(request);
Iterator<GFile> files;
files = Iterators.transform(iterator, new ToGFile(this));
return ImmutableList.copyOf(files);
} catch (IOException e) {
throw new GDriveException(e);
}
}
InputStream exportFileTxt(File file) {
return getContentsFromUrl(file.getExportLinks().get("text/plain"));
}
InputStream downloadFile(File file) {
return getContentsFromUrl(file.getDownloadUrl());
}
private InputStream getContentsFromUrl(String url) {
try {
InputStream res = null;
if (url != null && url.length() > 0) {
HttpResponse resp = service.getRequestFactory()
.buildGetRequest(new GenericUrl(url))
.execute();
res = resp.getContent();
}
return res;
} catch (IOException e) {
throw new GDriveException(e);
}
}
GDirectory mkdir(String directoryId, String dirName) {
try {
File content = new File();
content.setTitle(dirName);
content.setMimeType("application/vnd.google-apps.folder");
content.setParents(newArrayList(new ParentReference().setId(directoryId)));
File file = service
.files()
.insert(content)
.execute();
return new ToGDirectory(this, directoryId).apply(file);
} catch (IOException e) {
throw new GDriveException(e);
}
}
GFile insert(File body, FileContent mediaContent) {
try {
File file = service
.files()
.insert(body, mediaContent)
.execute();
GFile gfile = new GFileBuilder()
.drive(this)
.file(file)
.build();
return gfile;
} catch (IOException e) {
throw new GDriveException(e);
}
}
List<GChange> listChanges(String directoryId, Long startChangeId) {
try {
Changes.List _request = service
.changes()
.list();
RequestChange request = new RequestChange(_request);
if (startChangeId != null) {
_request.setStartChangeId(startChangeId);
}
Iterator<Change> iterator;
iterator = new RequestIterator<Change>(request);
Iterator<Change> filtered;
filtered = Iterators.filter(iterator, new FilterInDirectory(directoryId));
Iterator<GChange> changes;
changes = Iterators.transform(filtered, new ToGChange());
return ImmutableList.copyOf(changes);
} catch (Exception e) {
throw new GDriveException(e);
}
}
private class FilterInDirectory implements Predicate<Change> {
private final String directoryId;
public FilterInDirectory(String directoryId) {
this.directoryId = directoryId;
}
@Override
public boolean apply(Change input) {
List<String> ids;
File file = input.getFile();
boolean res = false;
if (file != null) {
ids = transform(file.getParents(), ParentReferenceToId.INSTANCE);
res = ids.contains(directoryId);
}
return res;
}
}
private enum ParentReferenceToId implements Function<ParentReference, String> {
INSTANCE;
@Override
public String apply(ParentReference input) {
return input.getIsRoot() ? "root" : input.getId();
}
}
private class ToGDirectory implements Function<File, GDirectory> {
private final GDrive drive;
private final String directoryId;
public ToGDirectory(GDrive drive, String directoryId) {
this.drive = drive;
this.directoryId = directoryId;
}
@Override
public GDirectory apply(File input) {
return new GDirectoryFolder(input, drive, directoryId);
}
}
private class ToGChange implements Function<Change, GChange> {
@Override
public GChange apply(Change input) {
GChange change = new GChangeBuilder()
.drive(GDrive.this)
.change(input)
.build();
return change;
}
}
}