com.android.volley1.toolbox.BasicNetwork.java Source code

Java tutorial

Introduction

Here is the source code for com.android.volley1.toolbox.BasicNetwork.java

Source

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 com.android.volley1.toolbox;

import android.os.SystemClock;
import android.util.Log;

import com.android.volley1.AuthFailureError;
import com.android.volley1.Cache.Entry;
import com.android.volley1.Network;
import com.android.volley1.NetworkError;
import com.android.volley1.NetworkResponse;
import com.android.volley1.NoConnectionError;
import com.android.volley1.Request;
import com.android.volley1.RetryPolicy;
import com.android.volley1.ServerError;
import com.android.volley1.TimeoutError;
import com.android.volley1.VolleyError;
import com.android.volley1.VolleyLog;
import com.android.volley1.http.HttpCodeDef;
import com.android.volley1.http.HttpResponse;

import org.apache.http.conn.ConnectTimeoutException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import okio.Okio;

/**
 * A network performing Volley requests over an {@link HttpStack}.
 */
public class BasicNetwork implements Network {
    protected static final boolean DEBUG = VolleyLog.DEBUG;

    private static final int SLOW_REQUEST_THRESHOLD_MS = 3000;

    private static final int DEFAULT_POOL_SIZE = 4096;
    private static final String TAG = "BasicNetwork";

    protected final HttpStack mHttpStack;

    protected final ByteArrayPool mPool;

    /**
     * @param httpStack HTTP stack to be used
     */
    public BasicNetwork(HttpStack httpStack) {
        // If a pool isn't passed in, then build a small default pool that will give us a lot of
        // benefit and not use too much memory.
        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
    }

    /**
     * @param httpStack HTTP stack to be used
     * @param pool      a buffer pool that improves GC performance in copy operations
     */
    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
        mHttpStack = httpStack;
        mPool = pool;
    }

    @Override
    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();
        while (true) {
            HttpResponse httpResponse = null;
            //            byte[] responseContents = null;
            Map<String, String> responseHeaders = Collections.emptyMap();
            try {
                // Gather headers.
                Map<String, String> headers = new HashMap<String, String>();
                addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = mHttpStack.performRequest(request, headers);

                int statusCode = httpResponse.getResponseCode();

                Log.e(TAG, statusCode + "");

                //                int statusCode = statusLine.getStatusCode();
                //                StatusLine statusLine = httpResponse.getStatusLine();

                responseHeaders = httpResponse.getHeaders();
                // Handle cache validation.

                if (statusCode == HttpCodeDef.SC_NOT_MODIFIED) {

                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(HttpCodeDef.SC_NOT_MODIFIED, responseHeaders, null, true,
                                SystemClock.elapsedRealtime() - requestStart);
                    }

                    // A HTTP 304 response does not have all header fields. We
                    // have to use the header fields from the cache entry plus
                    // the new ones from the response.
                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(HttpCodeDef.SC_NOT_MODIFIED, entry.responseHeaders,
                            Okio.source(new ByteArrayInputStream(entry.data)), true,
                            SystemClock.elapsedRealtime() - requestStart);
                }

                // Some responses such as 204s do not have content.  We must check.
                /*      if (httpResponse.getInputStream() != null) {
                    
                responseContents = streamToBytes(httpResponse);
                    
                    
                      } else {
                // Add 0 byte response as a way of honestly representing a
                // no-content request.
                responseContents = new byte[0];
                      }
                */
                // if the request is slow, log it.
                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                logSlowRequests(requestLifetime, request, /* responseContents,*/ statusCode);

                // FIXME: 4/13/16 ????
                if (statusCode < 200 || statusCode > 299) {
                    throw new IOException();
                }

                return new NetworkResponse(statusCode, responseHeaders, Okio.source(httpResponse.getInputStream()),
                        false, SystemClock.elapsedRealtime() - requestStart);

                /*        if (responseContents != null) {
                return new NetworkResponse(statusCode, responseHeaders, responseContents, false,
                        SystemClock.elapsedRealtime() - requestStart);
                        } else {
                    
                    
                return new NetworkResponse(statusCode, responseHeaders, httpResponse.getInputStream(), false,
                        SystemClock.elapsedRealtime() - requestStart);
                    
                    
                        }*/

            } catch (SocketTimeoutException e) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException e) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException e) {
                throw new RuntimeException("Bad URL " + request.getUrl(), e);
            } catch (IOException e) {
                int statusCode = 0;
                NetworkResponse networkResponse = null;
                if (httpResponse != null) {
                    statusCode = httpResponse.getResponseCode();
                } else {
                    throw new NoConnectionError(e);
                }
                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                if (httpResponse.getInputStream() != null) {
                    networkResponse = new NetworkResponse(statusCode, responseHeaders,
                            Okio.source(httpResponse.getInputStream()), false,
                            SystemClock.elapsedRealtime() - requestStart);
                    if (statusCode == HttpCodeDef.SC_UNAUTHORIZED || statusCode == HttpCodeDef.SC_FORBIDDEN) {
                        attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
                    } else {
                        // TODO: Only throw ServerError for 5xx status codes.
                        throw new ServerError(networkResponse);
                    }
                } else {
                    throw new NetworkError(networkResponse);
                }
            }
        }
    }

    private byte[] streamToBytes(HttpResponse response) throws IOException, ServerError {

        long contentLength = response.getContentLength();

        if (contentLength > 20 * 1024 * 1024) {
            VolleyLog.d("contentLength is so large so return stream %d ", contentLength);
            return null;
        }

        PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) contentLength);

        byte[] buffer = mPool.getBuf(1024);

        try {

            InputStream in = response.getInputStream();
            if (in == null) {
                throw new ServerError("response.getInputStream()= null");
            }

            int len;
            while ((len = in.read(buffer)) != -1) {
                bytes.write(buffer, 0, len);
            }

            String str = new String(bytes.toByteArray(), 0, bytes.size());
            System.out.println("str = " + str);

            return bytes.toByteArray();

        } finally {
            mPool.returnBuf(buffer);
            bytes.close();
        }

    }

    /**
     * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
     */
    private void logSlowRequests(long requestLifetime, Request<?> request,
            /*   byte[] responseContents,*/ int statusCode) {
        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
            VolleyLog.d("HTTP response for request=<%s> [lifetime=%d],  " + "[rc=%d], [retryCount=%s]", request,
                    requestLifetime,
                    /*  responseContents != null ? responseContents.length : "null",*/
                    statusCode, request.getRetryPolicy().getCurrentRetryCount());
        }
    }

    /**
     * Attempts to prepare the request for a retry. If there are no more attempts remaining in the
     * request's retry policy, a timeout exception is thrown.
     *
     * @param request The request to use.
     */
    private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception)
            throws VolleyError {
        RetryPolicy retryPolicy = request.getRetryPolicy();
        int oldTimeout = request.getTimeoutMs();

        try {
            retryPolicy.retry(exception);
        } catch (VolleyError e) {
            request.addMarker(String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
            throw e;
        }
        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
    }

    private void addCacheHeaders(Map<String, String> headers, Entry entry) {
        // If there's no cache entry, we're done.
        if (entry == null) {
            return;
        }

        if (entry.etag != null) {
            headers.put("If-None-Match", entry.etag);
        }

        if (entry.lastModified > 0) {
            Date refTime = new Date(entry.lastModified);
            //            headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
        }
    }

    protected void logError(String what, String url, long start) {
        long now = SystemClock.elapsedRealtime();
        VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
    }

    //    /** Reads the contents of HttpEntity into a byte[]. */
    //    private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
    //        PoolingByteArrayOutputStream bytes =
    //                new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
    //        byte[] buffer = null;
    //        try {
    //            InputStream in = entity.getContent();
    //            if (in == null) {
    //                throw new ServerError();
    //            }
    //            buffer = mPool.getBuf(1024);
    //            int count;
    //            while ((count = in.read(buffer)) != -1) {
    //                bytes.write(buffer, 0, count);
    //            }
    //            return bytes.toByteArray();
    //        } finally {
    //            try {
    //                // Close the InputStream and release the resources by "consuming the content".
    //                entity.consumeContent();
    //            } catch (IOException e) {
    //                // This can happen if there was an exception above that left the entity in
    //                // an invalid state.
    //                VolleyLog.v("Error occured when calling consumingContent");
    //            }
    //            mPool.returnBuf(buffer);
    //            bytes.close();
    //        }
    //    }

    //    /**
    //     * Converts Headers[] to Map<String, String>.
    //     */
    //    protected static Map<String, String> convertHeaders(Header[] headers) {
    //        Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
    //        for (int i = 0; i < headers.length; i++) {
    //            result.put(headers[i].getName(), headers[i].getValue());
    //        }
    //        return result;
    //    }
}