com.alibaba.shared.django.DjangoClient.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.shared.django.DjangoClient.java

Source

/*
 * Copyright 1999-2004 Alibaba.com All right reserved. This software is the confidential and proprietary information of
 * Alibaba.com ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into with Alibaba.com.
 */
package com.alibaba.shared.django;

import com.alibaba.fastjson.JSON;
import com.alibaba.shared.django.utils.Digests;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created with IntelliJ IDEA.
 *
 * @author zizhi.zhzzh
 *         Date: 3/3/14
 *         Time: 12:25 PM
 */
@Component
public class DjangoClient {

    public static final int MAX_CHUNK_SIZE = 6 * 1024 * 1024;

    public static final String ACCESS_TOKEN_KEY = "token";
    public static final String FILE_KEY = "file";

    private static final Logger LOGGER = LoggerFactory.getLogger("django");

    @Value("#{django.appKey}")
    private String appKey;
    @Value("#{django.appSecret}")
    private String appSecret;

    @Value("#{django.tokenUrl}")
    private String tokenUrl;
    @Value("#{django.uploadFileUrl}")
    private String uploadFileUrl;
    @Value("#{django.downloadFileUrl}")
    private String downloadFileUrl;
    @Value("#{django.transactionUrl}")
    private String transactionUrl;
    @Value("#{django.chunkUrl}")
    private String chunkUrl;
    @Value("#{django.metaUrl}")
    private String metaUrl;

    private String accessToken;

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private HttpClient httpClient = HttpClientBuilder.create().build();

    public String accessToken() {
        Lock rl = lock.readLock();
        rl.lock(); // Waiting for refresh!
        try {
            if (accessToken != null) {
                return accessToken;
            }
        } finally {
            rl.unlock();
        }
        if (accessToken == null) {
            try {
                refreshToken();
            } catch (URISyntaxException e) {
                LOGGER.error("refreshTokenError", e);
            } catch (IOException e) {
                LOGGER.error("refreshTokenError", e);
            }
        }
        return accessToken;
    }

    public DjangoMessage fileMetas(final String... fileIds) throws URISyntaxException, IOException {
        return executeRequest(new Supplier<HttpUriRequest>() {
            public HttpUriRequest get() {
                Map<String, String> params = Maps.newHashMap();
                params.put(ACCESS_TOKEN_KEY, accessToken());
                params.put("fileIds", join("|", fileIds));
                return new HttpGet(buildURI(metaUrl, params));
            }
        });
    }

    public byte[] downloadFile(String fileId) throws URISyntaxException, IOException {
        URI uri = new URIBuilder(downloadFileUrl).addParameter(ACCESS_TOKEN_KEY, accessToken())
                .addParameter("fileIds", fileId).build();
        HttpGet req = new HttpGet(uri);
        HttpResponse resp = getHttpClient().execute(req);
        if (resp.getStatusLine().getStatusCode() == 200) {
            return EntityUtils.toByteArray(resp.getEntity());
        }
        return null;
    }

    public DjangoMessage uploadFile(final byte[] bytes, final String filename)
            throws IOException, URISyntaxException {
        return executeRequest(new Supplier<HttpUriRequest>() {
            public HttpUriRequest get() {
                HttpPost post = new HttpPost(uploadFileUrl);
                MultipartEntityBuilder meb = MultipartEntityBuilder.create();
                meb.addTextBody(ACCESS_TOKEN_KEY, accessToken()).addTextBody("md5", Digests.md5(bytes))
                        .addBinaryBody(FILE_KEY, bytes, ContentType.APPLICATION_XML, filename);
                post.setEntity(meb.build());
                return post;
            }
        });
    }

    public String uploadFile(InputStream is, int maxChunkSize, long size, String filename, String ext)
            throws IOException, URISyntaxException {
        DjangoMessage message = beginUploadTransaction(size, ((int) size / maxChunkSize + 1), ext, null);
        String fileId = null;
        try {
            if (message.isSuccess()) {
                fileId = message.getString("id");
                if (fileId != null) {
                    List<DjangoMessage> djangoMessages = new ArrayList<DjangoMessage>();
                    uploadFileChunks(is, maxChunkSize, fileId, 1, filename, djangoMessages);
                    //TODO check djangoMessages
                }
            }
        } finally {
            if (fileId != null) {
                endUploadTransaction(fileId);
            }
        }
        return fileId;
    }

    public String getTokenUrl() {
        return tokenUrl;
    }

    public void setTokenUrl(String tokenUrl) {
        this.tokenUrl = tokenUrl;
    }

    public String getUploadFileUrl() {
        return uploadFileUrl;
    }

    public void setUploadFileUrl(String uploadFileUrl) {
        this.uploadFileUrl = uploadFileUrl;
    }

    public String getDownloadFileUrl() {
        return downloadFileUrl;
    }

    public void setDownloadFileUrl(String downloadFileUrl) {
        this.downloadFileUrl = downloadFileUrl;
    }

    public String getTransactionUrl() {
        return transactionUrl;
    }

    public void setTransactionUrl(String transactionUrl) {
        this.transactionUrl = transactionUrl;
    }

    public String getChunkUrl() {
        return chunkUrl;
    }

    public void setChunkUrl(String chunkUrl) {
        this.chunkUrl = chunkUrl;
    }

    public String getMetaUrl() {
        return metaUrl;
    }

    public void setMetaUrl(String metaUrl) {
        this.metaUrl = metaUrl;
    }

    protected void uploadFileChunks(InputStream is, int maxChunkSize, final String fileId, final int sequence,
            final String fillename, List<DjangoMessage> holder) throws IOException, URISyntaxException {
        final MessageDigest digest = Digests.defaultDigest();
        byte[] buf = new byte[8000];
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len = is.read(buf), processCount = len;
        while (len >= 0 && processCount < maxChunkSize) {
            baos.write(buf, 0, len);
            digest.update(buf, 0, len);
            processCount += len;
            if (maxChunkSize <= processCount) {
                break;
            }
            len = is.read(buf);
        }
        if (processCount > 0) {
            holder.add(executeRequest(new Supplier<HttpUriRequest>() {
                public HttpUriRequest get() {
                    MultipartEntityBuilder meb = MultipartEntityBuilder.create();
                    meb.addTextBody(ACCESS_TOKEN_KEY, accessToken()).addTextBody("fileId", fileId)
                            .addTextBody("sequence", String.valueOf(sequence))
                            .addTextBody("md5", Digests.toHexDigest(digest.digest())).addBinaryBody(FILE_KEY,
                                    baos.toByteArray(), ContentType.APPLICATION_OCTET_STREAM, fillename);
                    HttpPost post = new HttpPost(chunkUrl);
                    post.setEntity(meb.build());
                    return post;
                }
            }));
            uploadFileChunks(is, maxChunkSize, fileId, sequence + 1, fillename, holder);
        }
    }

    protected void refreshToken() throws URISyntaxException, IOException {
        Lock wl = lock.writeLock();
        wl.lock();
        try {
            final String timestamp = String.valueOf(new Date().getTime());
            DjangoMessage msg = executeRequest(new Supplier<HttpUriRequest>() {
                public HttpUriRequest get() {
                    Map<String, String> params = Maps.newHashMap();
                    params.put("appKey", appKey);
                    params.put("timestamp", timestamp);
                    params.put("signature", buildSignature(timestamp));
                    return new HttpGet(buildURI(tokenUrl, params, false));
                }
            }, false);
            if (msg != null && msg.isSuccess()) {
                accessToken = msg.getString(ACCESS_TOKEN_KEY);
                LOGGER.info("Received accessToken {}", accessToken);
            }
        } finally {
            wl.unlock();
        }
    }

    protected DjangoMessage beginUploadTransaction(final long size, final int blockCount, final String ext,
            final String digest) throws URISyntaxException, IOException {
        return executeRequest(new Supplier<HttpUriRequest>() {
            public HttpUriRequest get() {
                Map<String, String> params = Maps.newHashMap();
                params.put("size", String.valueOf(size));
                params.put("number", String.valueOf(blockCount));
                params.put("ext", ext);
                if (!Strings.isNullOrEmpty(digest)) {
                    params.put("md5", digest);
                }
                return new HttpGet(buildURI(transactionUrl, params));
            }
        });
    }

    protected DjangoMessage endUploadTransaction(final String fileId) throws URISyntaxException, IOException {
        return executeRequest(new Supplier<HttpUriRequest>() {
            public HttpUriRequest get() {
                Map<String, String> params = Maps.newHashMap();
                params.put("fileId", fileId);
                URI uri = buildURI(transactionUrl, params);
                return new HttpGet(uri);
            }
        });
    }

    protected String buildSignature(String timestamp) {
        StringBuilder sb = new StringBuilder();
        sb.append(appKey).append(timestamp).append(appSecret);
        return Digests.md5(sb.toString());
    }

    protected DjangoMessage executeRequest(Supplier<HttpUriRequest> requestSupplier)
            throws IOException, URISyntaxException {
        return executeRequest(requestSupplier, true);
    }

    protected DjangoMessage executeRequest(Supplier<HttpUriRequest> requestSupplier, boolean canRetry)
            throws IOException, URISyntaxException {
        DjangoMessage message = null;
        try {
            HttpResponse response = getHttpClient().execute(requestSupplier.get());
            if (response.getStatusLine().getStatusCode() == 200) {
                message = JSON.parseObject(EntityUtils.toByteArray(response.getEntity()), DjangoMessage.class);
                if (canRetry && message != null && message.isTokenExpired()) {
                    refreshToken();
                    message = executeRequest(requestSupplier, false);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return message;
    }

    protected URI buildURI(String baseUrl, Map<String, String> params) {
        return buildURI(baseUrl, params, true);
    }

    protected URI buildURI(String baseUrl, Map<String, String> params, boolean hasAccessToken) {
        try {
            URIBuilder builder = new URIBuilder(baseUrl);
            if (hasAccessToken) {
                builder.addParameter(ACCESS_TOKEN_KEY, accessToken());
            }
            for (String paramName : params.keySet()) {
                builder.addParameter(paramName, params.get(paramName));
            }
            return builder.build();
        } catch (URISyntaxException e) {
            throw new DjangoRequestException(e.getMessage(), e);
        }
    }

    protected static String join(String splitter, String... strings) {
        return Joiner.on(splitter).join(Arrays.asList(strings));
    }

    private HttpClient getHttpClient() {
        return httpClient;
    }

}