ch.cyberduck.core.googledrive.DriveWriteFeature.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.core.googledrive.DriveWriteFeature.java

Source

package ch.cyberduck.core.googledrive;

/*
 * Copyright (c) 2002-2016 iterate GmbH. All rights reserved.
 * https://cyberduck.io/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

import ch.cyberduck.core.Cache;
import ch.cyberduck.core.ConnectionCallback;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.features.AttributesFinder;
import ch.cyberduck.core.features.Find;
import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.http.AbstractHttpWriteFeature;
import ch.cyberduck.core.http.DelayedHttpEntityCallable;
import ch.cyberduck.core.http.HttpResponseOutputStream;
import ch.cyberduck.core.io.ChecksumCompute;
import ch.cyberduck.core.io.DisabledChecksumCompute;
import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.shared.DefaultAttributesFinderFeature;
import ch.cyberduck.core.shared.DefaultFindFeature;
import ch.cyberduck.core.transfer.TransferStatus;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

import static com.google.api.client.json.Json.MEDIA_TYPE;

public class DriveWriteFeature extends AbstractHttpWriteFeature<Void> implements Write<Void> {

    private final DriveSession session;
    private final Find finder;
    private final AttributesFinder attributes;

    public DriveWriteFeature(final DriveSession session) {
        this(session, new DefaultFindFeature(session), new DefaultAttributesFinderFeature(session));
    }

    public DriveWriteFeature(final DriveSession session, final Find finder, final AttributesFinder attributes) {
        super(finder, attributes);
        this.session = session;
        this.finder = finder;
        this.attributes = attributes;
    }

    @Override
    public Append append(final Path file, final Long length, final Cache<Path> cache) throws BackgroundException {
        if (finder.withCache(cache).find(file)) {
            final PathAttributes attributes = this.attributes.withCache(cache).find(file);
            return new Append(false, true).withSize(attributes.getSize()).withChecksum(attributes.getChecksum());
        }
        return Write.notfound;
    }

    @Override
    public boolean temporary() {
        return false;
    }

    @Override
    public boolean random() {
        return false;
    }

    @Override
    public HttpResponseOutputStream<Void> write(final Path file, final TransferStatus status,
            final ConnectionCallback callback) throws BackgroundException {
        final DelayedHttpEntityCallable<Void> command = new DelayedHttpEntityCallable<Void>() {
            @Override
            public Void call(final AbstractHttpEntity entity) throws BackgroundException {
                try {
                    final String base = session.getClient().getRootUrl();
                    // Initiate a resumable upload
                    final HttpEntityEnclosingRequestBase request;
                    if (status.isExists()) {
                        final String fileid = new DriveFileidProvider(session).getFileid(file,
                                new DisabledListProgressListener());
                        request = new HttpPatch(
                                String.format("%s/upload/drive/v3/files/%s?supportsTeamDrives=true", base, fileid));
                        if (StringUtils.isNotBlank(status.getMime())) {
                            request.setHeader(HttpHeaders.CONTENT_TYPE, status.getMime());
                        }
                        // Upload the file
                        request.setEntity(entity);
                    } else {
                        request = new HttpPost(String.format(
                                String.format(
                                        "%%s/upload/drive/v3/files?uploadType=resumable&supportsTeamDrives=%s",
                                        PreferencesFactory.get().getBoolean("googledrive.teamdrive.enable")),
                                base));
                        request.setEntity(new StringEntity(
                                "{\"name\": \"" + file.getName() + "\", \"parents\": [\""
                                        + new DriveFileidProvider(session).getFileid(file.getParent(),
                                                new DisabledListProgressListener())
                                        + "\"]}",
                                ContentType.create("application/json", "UTF-8")));
                        if (StringUtils.isNotBlank(status.getMime())) {
                            // Set to the media MIME type of the upload data to be transferred in subsequent requests.
                            request.addHeader("X-Upload-Content-Type", status.getMime());
                        }
                    }
                    request.addHeader(HTTP.CONTENT_TYPE, MEDIA_TYPE);
                    final HttpClient client = session.getHttpClient();
                    final HttpResponse response = client.execute(request);
                    try {
                        switch (response.getStatusLine().getStatusCode()) {
                        case HttpStatus.SC_OK:
                            break;
                        default:
                            throw new DriveExceptionMappingService()
                                    .map(new HttpResponseException(response.getStatusLine().getStatusCode(),
                                            response.getStatusLine().getReasonPhrase()));
                        }
                    } finally {
                        EntityUtils.consume(response.getEntity());
                    }
                    if (!status.isExists()) {
                        if (response.containsHeader(HttpHeaders.LOCATION)) {
                            final String putTarget = response.getFirstHeader(HttpHeaders.LOCATION).getValue();
                            // Upload the file
                            final HttpPut put = new HttpPut(putTarget);
                            put.setEntity(entity);
                            final HttpResponse putResponse = client.execute(put);
                            try {
                                switch (putResponse.getStatusLine().getStatusCode()) {
                                case HttpStatus.SC_OK:
                                case HttpStatus.SC_CREATED:
                                    break;
                                default:
                                    throw new DriveExceptionMappingService().map(
                                            new HttpResponseException(putResponse.getStatusLine().getStatusCode(),
                                                    putResponse.getStatusLine().getReasonPhrase()));
                                }
                            } finally {
                                EntityUtils.consume(putResponse.getEntity());
                            }
                        } else {
                            throw new DriveExceptionMappingService()
                                    .map(new HttpResponseException(response.getStatusLine().getStatusCode(),
                                            response.getStatusLine().getReasonPhrase()));
                        }
                    }
                    return null;
                } catch (IOException e) {
                    throw new DriveExceptionMappingService().map("Upload failed", e, file);
                }
            }

            @Override
            public long getContentLength() {
                return status.getLength();
            }
        };
        return this.write(file, status, command);
    }

    @Override
    public ChecksumCompute checksum(final Path file) {
        return new DisabledChecksumCompute();
    }
}