Java tutorial
/* * 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; // } }