Source:
public void run() throws IOException, InterruptedException { AssetIndex index = Utils.loadJson(getIndex(), AssetIndex.class); List<String> keys = new ArrayList<>(index.objects.keySet()); Collections.sort(keys); ExecutorService executorService = Executors.newFixedThreadPool(16); CopyOnWriteArrayList<String> downloadingFailedURL = new CopyOnWriteArrayList<>(); for (String key : keys) { Asset asset = index.objects.get(key); File target = Utils.getCache(getProject(), "assets", "objects", asset.getPath()); if (!target.exists() || !HashFunction.SHA1.hash(target).equals(asset.hash)) { URL url = new URL(RESOURCE_REPO + asset.getPath()); Runnable copyURLtoFile = () -> { try { getProject().getLogger().lifecycle("Downloading: " + url + " Asset: " + key); FileUtils.copyURLToFile(url, target, 10_000, 5_000); if (!HashFunction.SHA1.hash(target).equals(asset.hash)) { throw new IOException(key + " Hash dose march"); } } catch (IOException e) { downloadingFailedURL.add(key); getProject().getLogger().error("{} downloading fails.", key); e.printStackTrace(); } }; executorService.execute(copyURLtoFile); } } executorService.shutdown(); executorService.awaitTermination(8, TimeUnit.HOURS); if (!downloadingFailedURL.isEmpty()) { String errorMessage = ""; for (String key : downloadingFailedURL) { errorMessage = errorMessage + "Downloading failed Asset: " + key + "\n"; } errorMessage = errorMessage + "Don't panic. There are just some assets downloading fails, Maybe you should try to run again the task which you just ran."; throw new RuntimeException(errorMessage); } }

Target:
public void run() throws IOException, InterruptedException { AssetIndex index = Utils.loadJson(getIndex(), AssetIndex.class); List<String> keys = new ArrayList<>(index.objects.keySet()); Collections.sort(keys); ExecutorService executorService = Executors.newFixedThreadPool(16); CopyOnWriteArrayList<String> downloadingFailedURL = new CopyOnWriteArrayList<>(); for (String key : keys) { Asset asset = index.objects.get(key); File target = Utils.getCache(getProject(), "assets", "objects", asset.getPath()); if (!target.exists() || !HashFunction.SHA1.hash(target).equals(asset.hash)) { URL url = new URL(RESOURCE_REPO + asset.getPath()); Runnable copyURLtoFile = () -> { try { getProject().getLogger().lifecycle("Downloading: " + url + " Asset: " + key); FileUtils.copyURLToFile(url, target, 10_000, 5_000); if (!HashFunction.SHA1.hash(target).equals(asset.hash)) { downloadingFailedURL.add(key); Utils.delete(target); getProject().getLogger().error("{} Hash failed.", key); } } catch (IOException e) { downloadingFailedURL.add(key); getProject().getLogger().error("{} downloading fails.", key); e.printStackTrace(); } }; executorService.execute(copyURLtoFile); } } executorService.shutdown(); executorService.awaitTermination(8, TimeUnit.HOURS); if (!downloadingFailedURL.isEmpty()) { String errorMessage = ""; for (String key : downloadingFailedURL) { errorMessage = errorMessage + "Downloading failed Asset: " + key + "\n"; } errorMessage = errorMessage + "Don't panic. There are just some assets downloading fails, Maybe you should try to run again the task which you just ran."; throw new RuntimeException(errorMessage); } }