com.commonslibrary.commons.net.DefaultOkHttpIml.java Source code

Java tutorial

Introduction

Here is the source code for com.commonslibrary.commons.net.DefaultOkHttpIml.java

Source

/*******************************************************************************
 *
 * Copyright (c) 2016 Mickael Gizthon . All rights reserved. Email:2013mzhou@gmail.com
 *
 * 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 com.commonslibrary.commons.net;

import android.text.TextUtils;

import com.commonslibrary.commons.config.SystemConfig;
import com.commonslibrary.commons.handler.WeakHandlerNew;
import com.commonslibrary.commons.utils.EncryptionUtils;
import com.commonslibrary.commons.utils.LogUtils;
import com.commonslibrary.commons.utils.StringUtils;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPOutputStream;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * date        :  2015-11-30  10:41
 * author      :  Mickaecle gizthon
 * description :  http  ,??json ?? 
 */
public class DefaultOkHttpIml implements IRequestRemote {

    private WeakHandlerNew mHandler;
    private Object tag = DefaultOkHttpIml.class;
    private static DefaultOkHttpIml mInstance;
    private OkHttpClient mOkHttpClient;

    private DefaultOkHttpIml() {
        mHandler = new WeakHandlerNew();
        File file = new File(SystemConfig.getSystemCacheDir());
        Cache cache = new Cache(file, 10 * 1024 * 1024);
        mOkHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
                .readTimeout(15, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).cache(cache)
                //                .addInterceptor(new GzipRequestInterceptor())
                .addInterceptor(new LoggingInterceptor()).build();
    }

    public static DefaultOkHttpIml getInstance() {
        if (null == mInstance) {
            synchronized (DefaultOkHttpIml.class) {
                if (null == mInstance) {
                    mInstance = new DefaultOkHttpIml();
                }
            }
        }
        return mInstance;
    }

    class LoggingInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request request = chain.request();

            long t1 = System.nanoTime();
            Response response = chain.proceed(request);
            long t2 = System.nanoTime();
            LogUtils.i(String.format(Locale.getDefault(), "%s take %.1fms%s", response.request().url(),
                    (t2 - t1) / 1e6d, ""/*response.headers()*/));

            return response;
        }
    }

    @Override
    public <T> void doGet(String url, Map<String, Object> parameters, RequestCallBack<T> callBack) {

        if (callBack != null) {
            callBack.onStart();
        }
        if (parameters == null) {
            parameters = new HashMap<>();
        }

        String requestUrl = url + "?" + StringUtils.formatUrl(parameters);

        printLog(requestUrl, null);

        Request request = new Request.Builder().url(requestUrl).tag(tag).get().build();
        execute(mOkHttpClient.newCall(request), null, callBack);
    }

    @Override
    public <T> void doPost(String url, Map<String, Object> parameters, RequestCallBack<T> callBack) {
        if (callBack != null) {
            callBack.onStart();
        }

        FormBody.Builder builder = new FormBody.Builder();

        addParams(url, parameters, builder);
        RequestBody body = builder.build();

        Request request = new Request.Builder().url(url).post(body).tag(tag).build();
        execute(mOkHttpClient.newCall(request), null, callBack);

    }

    @Deprecated
    public <T> void doPost(String url, String json, final RequestCallBack<T> callBack) {
        if (callBack != null) {
            callBack.onStart();
        }
        final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder().url(url).post(body).tag(tag).build();
        OkHttpClient mOkHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
                .readTimeout(15, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).socketFactory(null).build();

        execute(mOkHttpClient.newCall(request), null, callBack);
    }

    @Override
    public <T> void doUpload(String url, Map<String, Object> parameters, Map<String, File> files,
            final RequestCallBack<T> callBack) {
        if (callBack != null) {
            callBack.onStart();
        }

        MultipartBody.Builder builder = new MultipartBody.Builder();
        addParams(url, parameters, files, builder);

        RequestBody requestBody = builder.build();
        Request request = new Request.Builder().url(url).post(new ProgressRequestBody(requestBody, callBack))
                .tag(tag).build();

        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                sendFailResultCallback(null, ",???!", new Exception(""), callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response == null || !response.isSuccessful()) {
                    sendFailResultCallback(response, ",???!", new Exception(""),
                            callBack);
                    return;
                }

                sendSuccessResultCallback(response, response.body().string(), callBack);
            }
        });

    }

    @Override
    public <T> void doDownLoad(String url, Map<String, Object> parameters, final RequestCallBack<T> callBack) {
        if (callBack != null) {
            callBack.onStart();
        }
        if (parameters == null) {
            parameters = new HashMap<>();
        }

        if (!parameters.containsKey("fileName")) {
            if (callBack != null) {
                callBack.onFailure("??", new IllegalArgumentException(""));
            }
            LogUtils.e("??");
            return;
        }
        String md5 = "";
        if (parameters.containsKey("md5")) {
            md5 = (String) parameters.get("md5");
            if (md5.equals("null") || md5.trim().equals("")) {
                md5 = "";
                LogUtils.e("md5???md5");
            }
        } else {
            LogUtils.e("md5???md5");
        }

        final String fileMd5 = md5;

        final String destFileName = StringUtils.optionValue(parameters, "fileName");

        //clear ?
        parameters.remove("fileName");

        String downLoadUrl = url + "?" + StringUtils.formatUrl(parameters);

        Request request = new Request.Builder().url(downLoadUrl).tag(tag).build();

        final String errorMessage = ",?!";
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                sendFailResultCallback(null, errorMessage, e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response == null || !response.isSuccessful()) {
                    sendFailResultCallback(response, errorMessage, new Exception(""), callBack);
                    return;
                }
                saveFile(response, destFileName, callBack, fileMd5);
            }
        });

    }

    /**
     * ??
     *
     * @param callBack ?
     */

    private <T> void execute(Call call, String errorMessage, final RequestCallBack<T> callBack) {
        if (TextUtils.isEmpty(errorMessage)) {
            errorMessage = "??,???!";
        }
        try {
            final String finalErrorMessage = errorMessage;
            call.enqueue(new Callback() {

                @Override
                public void onFailure(Call call, final IOException e) {
                    sendFailResultCallback(null, finalErrorMessage, e, callBack);
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response == null || !response.isSuccessful()) {
                        sendFailResultCallback(response, finalErrorMessage, new Exception(finalErrorMessage),
                                callBack);
                        return;
                    }
                    sendSuccessResultCallback(response, response.body().string(), callBack);
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
            sendFailResultCallback(null, errorMessage, new Exception(errorMessage), callBack);
        }
    }

    /**
     * 
     *
     * @param error    ?
     * @param e        
     * @param callBack ?
     */
    public <T> void sendFailResultCallback(Response response, final String error, final Exception e,
            final RequestCallBack<T> callBack) {
        try {
            if (response == null) {
                LogUtils.i(e.toString());
            } else {
                LogUtils.i(response.body().string());
            }
        } catch (Exception e1) {
            e1.printStackTrace();
            if (response != null)
                LogUtils.i(response.message());
        }

        if (callBack == null)
            return;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                failed(error, e, callBack);
            }
        });

    }

    private <T> void failed(String error, Exception e, RequestCallBack<T> callBack) {
        if (TextUtils.isEmpty(error)) {
            callBack.onFailure(",???!", new Exception("Unexpected code " + e));
        } else {
            callBack.onFailure(error, new Exception("Unexpected code " + e));
        }
    }

    /**
     * ?
     *
     * @param response ?
     * @param result   
     * @param callBack ?
     */
    public <T> void sendSuccessResultCallback(final Response response, final String result,
            final RequestCallBack<T> callBack) {
        LogUtils.i(result);

        if (callBack == null)
            return;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                success(response, result, callBack);
            }
        });
    }

    @SuppressWarnings("unchecked")
    private <T> void success(Response response, String result, RequestCallBack<T> callBack) {
        callBack.onSuccess(response.body().charStream());
        Type type = getSuperClassGenricType(callBack.getClass(), 0);
        if (type == String.class) {
            callBack.onSuccess((T) result);
        } else {
            try {
                T t = fromJson(result, type);
                if (t != null) {
                    callBack.onSuccess(t);
                } else {
                    callBack.onFailure("??", new JsonSyntaxException("??"));
                }
            } catch (Exception e) {
                e.printStackTrace();
                callBack.onFailure("??", e);
            }

        }
    }

    @SuppressWarnings("unchecked")
    public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
        T t;
        try {
            if (typeOfT == String.class) {//string 
                return (T) json;
            }
            t = new Gson().fromJson(json, typeOfT);
        } catch (Exception e) {
            return null;
        }
        return t;
    }

    @SuppressWarnings("unchecked")
    public <T> T fromJson(Reader json, Type typeOfT) throws JsonSyntaxException {
        T t;
        try {
            if (typeOfT == String.class) {//string 
                return (T) json;
            }
            t = new Gson().fromJson(json, typeOfT);
        } catch (Exception e) {
            return null;
        }
        return t;
    }

    /**
     * ?
     *
     * @param response     ?
     * @param destFileName ??
     * @param callBack     
     * @throws IOException
     */
    public <T> void saveFile(final Response response, String destFileName, final RequestCallBack<T> callBack,
            final String fileMd5) throws IOException {
        String destFileDir = SystemConfig.getSystemFileDir();
        InputStream is = null;
        byte[] buf = new byte[2048];
        int len;
        FileOutputStream fos = null;
        File file = null;
        long total = 0;
        try {
            is = response.body().byteStream();
            total = response.body().contentLength();
            long sum = 0;

            LogUtils.e("?:" + total);

            File dir = new File(destFileDir);
            if (!dir.exists()) {
                boolean createSuccess = dir.mkdirs();
                LogUtils.i("?," + (createSuccess ? "?" : ""));
            }
            file = new File(dir, destFileName);

            if (file.exists()) {
                boolean deleteSuccess = file.delete();
                LogUtils.i("?," + (deleteSuccess ? "?" : ""));
            }

            fos = new FileOutputStream(file);
            final long finalTotal = total;
            while ((len = is.read(buf)) != -1) {
                sum += len;
                fos.write(buf, 0, len);
                final long finalSum = sum;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.onProgress(finalSum, finalTotal, finalTotal == finalSum);
                    }
                });
            }
            fos.flush();

        } catch (Exception e) {
            if (file != null) {
                boolean deleteSuccess = file.delete();
                LogUtils.i("," + (deleteSuccess ? "?" : ""));
            }
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (fos != null)
                    fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (checkFileIsDownloadSuccess(fileMd5, file, total)) {
                sendSuccessResultCallback(response, file.getAbsolutePath(), callBack);
            } else {
                if (file != null) {
                    boolean deleteSuccess = file.delete();
                    LogUtils.i("," + (deleteSuccess ? "?" : ""));
                }
                sendFailResultCallback(response, "!", new Exception(""), callBack);
            }
        }
    }

    private boolean checkFileIsDownloadSuccess(String fileMd5, File file, long total) throws IOException {
        return (file != null && file.exists()) && (total == file.length())
                && (TextUtils.isEmpty(fileMd5) || (!TextUtils.isEmpty(fileMd5)
                        && TextUtils.equals(EncryptionUtils.encryptMD5File2String(file), fileMd5)));
    }

    /**
     * ?
     *
     * @param url        url
     * @param parameters ?
     */
    private void printLog(String url, Map<String, Object> parameters) {
        if (parameters == null) {
            LogUtils.i(url);
        } else {
            String requestUrl = url + "?" + StringUtils.formatUrl(parameters);
            LogUtils.i(requestUrl);
        }
    }

    /**
     * 
     *
     * @param path 
     * @return 
     */
    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

    /**
     * ? fileKey ??
     *
     * @param url     url
     * @param params  ?
     * @param files   
     * @param builder ?
     */
    private void addParams(String url, Map<String, Object> params, Map<String, File> files,
            MultipartBody.Builder builder) {

        if (params == null || params.isEmpty()) {
            params = new HashMap<>();
        }

        printLog(url, params);//?url

        for (Map.Entry<String, Object> entry : params.entrySet()) {
            builder.addFormDataPart(entry.getKey(), String.valueOf(entry.getValue()));
        }

        for (Map.Entry<String, File> entry : files.entrySet()) {
            File file = entry.getValue();
            if (file.exists()) {
                builder.addFormDataPart(entry.getKey(), file.getName(),
                        RequestBody.create(MediaType.parse(guessMimeType(file.getName())), file));
            }
        }

    }

    /**
     * ?
     *
     * @param url     url
     * @param params  ?
     * @param builder ?
     */
    private void addParams(String url, Map<String, Object> params, FormBody.Builder builder) {

        if (params == null || params.isEmpty()) {
            params = new HashMap<>();
        }

        printLog(url, params);//?url

        for (String key : params.keySet()) {
            builder.add(key, String.valueOf(params.get(key)));
        }

    }

    /**
     * ?tag
     *
     * @param tag tagactivity? tag,activity??
     */
    public DefaultOkHttpIml setTag(Object tag) {
        this.tag = tag;
        return this;
    }

    /**
     * ??
     *
     * @param tag ?tagactivity
     */
    public void cancelTag(Object tag) {
        if (mOkHttpClient == null) {
            return;
        }
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    public void cancelAllTag() {
        if (mOkHttpClient == null) {
            return;
        }
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            call.cancel();
        }
        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            call.cancel();
        }
    }

    /**
     * gzip;
     * gzip way to compress data;
     *
     * @param val ?
     * @return ?bytes?
     * @throws IOException 
     */
    private static byte[] gzip(byte[] val) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream(val.length);
        GZIPOutputStream gos = null;
        try {
            gos = new GZIPOutputStream(bos);
            gos.write(val, 0, val.length);
            gos.finish();
            val = bos.toByteArray();
            bos.flush();
        } finally {
            if (gos != null) {
                //gos?finish???
            }
            if (bos != null) {
                bos.close();
            }
        }
        return val;
    }

    public static Type getSuperClassGenricType(final Class clazz, final int index) {

        // Class ??? void Type
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }
        //? Type 
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            return Object.class;
        }

        return params[index];
    }

}