All Downloads are FREE. Search and download functionalities are using the official Maven repository.

syncloud.google.docs.ResumableUploader Maven / Gradle / Ivy

The newest version!
package syncloud.google.docs;

import com.google.api.client.http.*;
import com.google.api.client.http.xml.atom.AtomContent;
import syncloud.core.CoreException;
import syncloud.core.log.Logger;
import syncloud.google.docs.model.DocsUrl;
import syncloud.google.docs.model.Entry;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ResumableUploader {

    private static Logger logger = Logger.getLogger(ResumableUploader.class);
    public final int CHUNK_SIZE = 262144;
    private RequestExecutor requestExecutor;

    public ResumableUploader() {
        this.requestExecutor = new RequestExecutor();
    }

    public RequestExecutor getRequestExecutor() {
        return requestExecutor;
    }

    private String uploadChunk(byte[] bytes, int position, int length, String fileType, HttpRequestFactory requestFactory, long size, String location) {

        String newLocation = location;

        try {

            putRequest(bytes, position, length, fileType, requestFactory, size, location);

        } catch (HttpResponseException e) {
            if (e.getResponse().getStatusCode() == 308) {
                newLocation = getNextLocation(newLocation, e);
            } else {
                String message = "unable to upload a chunk, response: " + e.getMessage();
                logger.debug(message);
                throw new CoreException(message, e);
            }
        }

        return newLocation;
    }

    private String getNextLocation(String newLocation, HttpResponseException e) {
        try {
            String tempLocation = e.getResponse().getHeaders().getLocation();
            if (tempLocation != null) {
                newLocation = tempLocation;
            }
            e.getResponse().ignore();
        } catch (IOException e1) {
            String message = "unable to ignore response, " + e1.getMessage();
            logger.error(message);
            throw new CoreException(message, e1);
        }
        return newLocation;
    }

    private Entry uploadLastChunk(byte[] bytes, int position, int length, String fileType, HttpRequestFactory requestFactory, long size, String location) {

        try {

            HttpResponse response = putRequest(bytes, position, length, fileType, requestFactory, size, location);
            if (!response.isSuccessStatusCode()) {
                String message = "upload finished, but there was an error during upload, " + response.getStatusCode() + ": " + response.getStatusMessage();
                logger.error(message);
                throw new CoreException(message);
            }

            return response.parseAs(Entry.class);
        } catch (IOException e) {
            String message = "unable to parse response " + e.getMessage();
            logger.error(message);
            throw new CoreException(message);
        }
    }

    private HttpResponse putRequest(byte[] bytes, int position, int length, String fileType, HttpRequestFactory requestFactory, long size, String location) throws HttpResponseException {
        try {
            InputStreamContent inputStreamContent = new InputStreamContent(fileType, new ByteArrayInputStream(bytes));
            HttpRequest chunkRequest = requestFactory.buildPutRequest(new DocsUrl(location), inputStreamContent);
            chunkRequest.getHeaders().setContentRange(range(position, length, size));
            chunkRequest.getHeaders().setContentLength(String.valueOf(length));
            return requestExecutor.executeNonSensitive(chunkRequest);
        } catch (HttpResponseException e) {
            throw e;
        } catch (Exception e) {
            String message = "unable to upload chunk number " + position + ", " + e.getMessage();
            logger.error(message);
            throw new CoreException(message, e);
        }
    }

    private String initUpload(HttpRequestFactory requestFactory, DocsUrl url, long size, String fileType, AtomContent fileContent) throws IOException {
        HttpRequest request = requestFactory.buildPostRequest(url, fileContent);
        request.getHeaders().set("X-Upload-Content-Type", fileType);
        request.getHeaders().set("X-Upload-Content-Length", size);
        HttpResponse response = requestExecutor.executeNonSensitive(request);

        if (!response.isSuccessStatusCode()) {
            throw new CoreException("unable to initiate upload, " + response.getStatusCode() + ": " + response.getStatusMessage());
        }
        response.ignore();
        return response.getHeaders().getLocation();
    }

    public String range(long startByte, long length, long size) {
        long endByte = startByte;
        if (length > 0)
            endByte = startByte + (length - 1);
        return "bytes " + startByte + "-" + endByte + "/" + size;
    }

    public Entry createFileContent(final HttpRequestFactory requestFactory, final DocsUrl url, final InputStream is, final long size, final String fileType, AtomContent fileContent) throws IOException {

        String location = initUpload(requestFactory, url, size, fileType, fileContent);

        ChunkUploader uploader = new ChunkUploader(size, location) {

            @Override
            protected String onChunk(byte[] bytes, int position, int length, String location) {
                return uploadChunk(bytes, position, length, fileType, requestFactory, size, location);
            }

            @Override
            protected Entry onLastChunk(byte[] bytes, int position, int length, String location) {
                return uploadLastChunk(bytes, position, length, fileType, requestFactory, size, location);
            }
        };

        return uploader.upload(is, CHUNK_SIZE);

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy