Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: adblockplussbrowser/src/main/java/org/adblockplus/sbrowser/contentblocker/engine/Downloader.java

Issue 29603697: Issue 5931 - Create tests for util package (Closed)
Patch Set: Created Nov. 10, 2017, 2:23 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: adblockplussbrowser/src/main/java/org/adblockplus/sbrowser/contentblocker/engine/Downloader.java
===================================================================
new file mode 100644
--- /dev/null
+++ b/adblockplussbrowser/src/main/java/org/adblockplus/sbrowser/contentblocker/engine/Downloader.java
@@ -0,0 +1,261 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.adblockplus.sbrowser.contentblocker.engine;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+import android.annotation.SuppressLint;
+import android.util.Log;
+
+@SuppressLint("DefaultLocale")
+final class Downloader
+{
+ private static final int MAX_RETRIES = 5;
+
+ private static final String TAG = Downloader.class.getSimpleName();
+ private final Engine engine;
+ private final ReentrantLock accessLock = new ReentrantLock();
+ private Thread downloaderThread;
+ private final LinkedBlockingQueue<DownloadJob> downloadJobs = new LinkedBlockingQueue<>();
+ private final HashSet<String> enqueuedIds = new HashSet<>();
+ private boolean downloaderEnabled = true;
+
+ private Downloader(final Engine engine)
+ {
+ this.engine = engine;
+ }
+
+ void lock()
+ {
+ this.accessLock.lock();
+ }
+
+ void unlock()
+ {
+ this.accessLock.unlock();
+ }
+
+ void connectivityChanged()
+ {
+ this.lock();
+ if (!this.downloaderEnabled)
+ {
+ Log.d(TAG, "Re-checking download permission");
+ }
+ this.downloaderEnabled = true;
+ this.unlock();
+ }
+
+ static void download(final DownloadJob job) throws IOException
+ {
+ final HttpURLConnection connection = (HttpURLConnection) job.url.openConnection();
+ connection.setRequestMethod("GET");
+ for (final Entry<String, String> e : job.headers.entrySet())
+ {
+ connection.addRequestProperty(e.getKey(), e.getValue());
+ }
+ connection.connect();
+
+ job.responseCode = connection.getResponseCode();
+ job.responseHeaders.clear();
+ job.responseText = null;
+
+ for (int i = 1;; i++)
+ {
+ final String key = connection.getHeaderFieldKey(i);
+ if (key == null)
+ {
+ break;
+ }
+ final String value = connection.getHeaderField(i);
+ job.responseHeaders.put(key.toLowerCase(), value);
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ try (final BufferedReader r = new BufferedReader(new InputStreamReader(
+ connection.getInputStream(), StandardCharsets.UTF_8)))
+ {
+ for (int ch = r.read(); ch != -1; ch = r.read())
+ {
+ sb.append((char) ch);
+ }
+ job.responseText = sb.toString();
+ }
+ }
+
+ public void enqueueDownload(final URL url, final String id, final Map<String, String> headers)
+ {
+ this.lock();
+ try
+ {
+ if (!this.enqueuedIds.contains(id))
+ {
+ this.enqueuedIds.add(id);
+ this.downloadJobs.add(new DownloadJob(url, id, headers));
+ }
+ }
+ finally
+ {
+ this.unlock();
+ }
+ }
+
+ public static Downloader create(final Engine engine)
+ {
+ final Downloader downloader = new Downloader(engine);
+
+ downloader.downloaderThread = new Thread(new DownloaderHandler(downloader));
+ downloader.downloaderThread.setDaemon(true);
+ downloader.downloaderThread.start();
+
+ return downloader;
+ }
+
+ private static class DownloaderHandler implements Runnable
+ {
+ private static final String TAG = DownloaderHandler.class.getSimpleName();
+
+ private final Downloader downloader;
+
+ public DownloaderHandler(final Downloader downloader)
+ {
+ this.downloader = downloader;
+ }
+
+ @Override
+ public void run()
+ {
+ Log.d(TAG, "Handler thread started");
+ final LinkedBlockingQueue<DownloadJob> reQueue = new LinkedBlockingQueue<>();
+ boolean interrupted = false;
+ while (!interrupted)
+ {
+ DownloadJob job = null;
+ try
+ {
+ if (!this.downloader.downloaderEnabled)
+ {
+ Thread.sleep(30000);
+ continue;
+ }
+ job = this.downloader.downloadJobs.poll(5 * 60, TimeUnit.SECONDS);
+ if (job != null)
+ {
+ if (this.downloader.engine.canUseInternet())
+ {
+ Log.d(TAG, "Downloading '" + job.id + "' using " + job.url);
+ download(job);
+ Log.d(TAG, "Downloading '" + job.id + "' finished with response code "
+ + job.responseCode);
+ this.downloader.lock();
+ try
+ {
+ this.downloader.enqueuedIds.remove(job.id);
+ }
+ finally
+ {
+ this.downloader.unlock();
+ }
+
+ this.downloader.engine.downloadFinished(job.id, job.responseCode, job.responseText,
+ job.responseHeaders);
+
+ // Check for retries
+ if (!reQueue.isEmpty())
+ {
+ this.downloader.downloadJobs.add(reQueue.poll());
+ }
+ }
+ else
+ {
+ // we just keep jobs in queue
+ Log.d(TAG, "Updates disabled, re-queuing and disabling downloader");
+ this.downloader.downloadJobs.add(job);
+ this.downloader.lock();
+ this.downloader.downloaderEnabled = false;
+ this.downloader.unlock();
+ }
+ }
+ }
+ catch (final InterruptedException e)
+ {
+ Log.d(TAG, "Handler interrupted", e);
+ interrupted = true;
+ }
+ catch (final Throwable t)
+ {
+ Log.e(TAG, "Downloading failed: " + t.getMessage(), t);
+ if (job != null)
+ {
+ if (job.retryCount++ < MAX_RETRIES)
+ {
+ reQueue.add(job);
+ }
+ else
+ {
+ this.downloader.lock();
+ try
+ {
+ this.downloader.enqueuedIds.remove(job.id);
+ }
+ finally
+ {
+ this.downloader.unlock();
+ }
+ this.downloader.engine.downloadFinished(job.id, -1, null, null);
+ }
+ }
+ }
+ }
+ Log.d(TAG, "Handler thread finished");
+ }
+ }
+
+ private static class DownloadJob
+ {
+ private final URL url;
+ private final String id;
+ private final HashMap<String, String> headers = new HashMap<>();
+ private int retryCount = 0;
+
+ private int responseCode = 0;
+ private final HashMap<String, String> responseHeaders = new HashMap<>();
+ private String responseText = null;
+
+ public DownloadJob(final URL url, final String id, final Map<String, String> headers)
+ {
+ this.url = url;
+ this.id = id;
+ if (headers != null)
+ {
+ this.headers.putAll(headers);
+ }
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld