Advertisement
alyoshinkkaa

Untitled

Apr 25th, 2024 (edited)
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.68 KB | None | 0 0
  1. package info.kgeorgiy.ja.shinkareva.crawler;
  2.  
  3. import info.kgeorgiy.java.advanced.crawler.*;
  4.  
  5. import java.io.IOException;
  6. import java.net.MalformedURLException;
  7. import java.util.*;
  8. import java.util.concurrent.*;
  9.  
  10. import static info.kgeorgiy.java.advanced.crawler.URLUtils.getHost;
  11.  
  12. public class WebCrawler implements NewCrawler {
  13.     private final Downloader downloader;
  14.     private final ExecutorService downloaders;
  15.     private final ExecutorService extractors;
  16.     private final int perHost;
  17.     private final Map<String, HostSemaphore> hosts;
  18.     private final Set<String> downloaded = new CopyOnWriteArraySet<>();
  19.     private final Map<String, IOException> errors = new ConcurrentHashMap<>();
  20.     private final Set<String> usedLinks = new CopyOnWriteArraySet<>();
  21.     private final Phaser phaser = new Phaser(1);
  22.  
  23.     public WebCrawler(Downloader downloader, int downloaders, int extractors, int perHost) {
  24.         this.downloader = downloader;
  25.         this.downloaders = Executors.newFixedThreadPool(downloaders);
  26.         this.extractors = Executors.newFixedThreadPool(extractors);
  27.         this.perHost = perHost;
  28.         this.hosts = new ConcurrentHashMap<>();
  29.     }
  30.  
  31.     @Override
  32.     public Result download(String url, int depth, Set<String> excludes) {
  33.         usedLinks.add(url);
  34.         final Set<String> currUrls = new CopyOnWriteArraySet<>();
  35.         final Set<String> newUrls = new CopyOnWriteArraySet<>();
  36.         currUrls.add(url);
  37.         for (int i = 0; i < depth; i++) {
  38.             for (var prevUrl : currUrls) {
  39.                 download(prevUrl, depth - i, newUrls, excludes);
  40.             }
  41.             phaser.arriveAndAwaitAdvance();
  42.             currUrls.clear();
  43.             currUrls.addAll(newUrls);
  44.             newUrls.clear();
  45.         }
  46.         return new Result(new ArrayList<>(downloaded), errors);
  47.     }
  48.  
  49.     private boolean checkUrl(String url, Set<String> excludes) {
  50.         for (String ex : excludes) {
  51.             if (url.contains(ex)) {
  52.                 return true;
  53.             }
  54.         }
  55.         return false;
  56.     }
  57.  
  58.     private void download(String url, int depth, Set<String> currenUrls, Set<String> excludes) {
  59.         if (!checkUrl(url, excludes)) {
  60.             try {
  61.                 HostSemaphore hostSemaphore = hosts.computeIfAbsent(getHost(url), s -> new HostSemaphore());
  62.                 phaser.register();
  63.                 hostSemaphore.add(() -> {
  64.                         try {
  65.                             Document doc = downloader.download(url);
  66.                             downloaded.add(url);
  67.                             if (depth > 1) {
  68.                                 phaser.register();
  69.                                 extractors.submit(() -> {
  70.                                     try {
  71.                                         List<String> extractLinks = doc.extractLinks();
  72.                                         for (String currUrl : extractLinks) {
  73.                                             if (!usedLinks.contains(currUrl)) {
  74.                                                 if (!checkUrl(currUrl, excludes)) {
  75.                                                     usedLinks.add(currUrl);
  76.                                                     currenUrls.add(currUrl);
  77.                                                 }
  78.                                             }
  79.                                         }
  80.                                     } catch (IOException e) {
  81.                                         errors.put(url, e);
  82.                                     } finally {
  83.                                         phaser.arriveAndDeregister();
  84.                                     }
  85.                                 });
  86.                             }
  87.                         } catch (IOException e) {
  88.                             errors.put(url, e);
  89.                         } finally {
  90.                             phaser.arriveAndDeregister();
  91.                             hostSemaphore.runNewTask();
  92.                         }
  93.                     });
  94.             } catch (MalformedURLException e) {
  95.                 errors.put(url, e);
  96.             }
  97.         }
  98.     }
  99.  
  100.     @Override
  101.     public void close() {
  102.         downloaders.shutdownNow();
  103.         extractors.shutdownNow();
  104.     }
  105.  
  106.     private class HostSemaphore {
  107.         private final Queue<Runnable> notWorkingTasks;
  108.         private int countOfLoading = 0;
  109.  
  110.         private HostSemaphore() {
  111.             this.notWorkingTasks = new ConcurrentLinkedDeque<>();
  112.         }
  113.  
  114.         private void add(Runnable task) {
  115.             if (countOfLoading < perHost) {
  116.                 downloaders.submit(task);
  117.                 countOfLoading++;
  118.             } else {
  119.                 notWorkingTasks.add(task);
  120.             }
  121.         }
  122.  
  123.         private void runNewTask() {
  124.             var task = notWorkingTasks.poll();
  125.             if (Objects.nonNull(task)) {
  126.                 downloaders.submit(task);
  127.             } else {
  128.                 countOfLoading--;
  129.             }
  130.         }
  131.     }
  132.  
  133.     public static void main(String[] args) {
  134.         if (args == null || args.length != 5 || Arrays.stream(args).anyMatch(Objects::isNull)) {
  135.             System.out.println("Invalid input format. Please follow this format:\nWebCrawler url [depth [downloads [extractors [perHost]]]]");
  136.         } else {
  137.             try {
  138.                 WebCrawler webCrawler = new WebCrawler(new CachingDownloader(1), Integer.parseInt(args[2]), Integer.parseInt(args[3]), Integer.parseInt(args[4]));
  139.                 webCrawler.download(args[0], Integer.parseInt(args[1]));
  140.             } catch (IOException e) {
  141.                 System.out.println("IOException: " + e.getMessage());
  142.             }
  143.         }
  144.     }
  145. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement