diff --git a/w11/Command.java b/w11/Command.java new file mode 100644 index 0000000..52f0e15 --- /dev/null +++ b/w11/Command.java @@ -0,0 +1,9 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import java.util.List; + +public interface Command { + String getName(); + void execute(String[] args, List
articles); +} \ No newline at end of file diff --git a/w11/CrawlCommand.java b/w11/CrawlCommand.java new file mode 100644 index 0000000..9debb15 --- /dev/null +++ b/w11/CrawlCommand.java @@ -0,0 +1,81 @@ +package com.example.datacollect.command; + +import com.example.datacollect.exception.CrawlerException; +import com.example.datacollect.model.Article; +import com.example.datacollect.repository.ArticleRepository; +import com.example.datacollect.service.ScraperService; +import com.example.datacollect.strategy.ArticleCrawlStrategy; +import com.example.datacollect.view.ConsoleView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.List; + +public class CrawlCommand implements Command { + private static final Logger logger = LoggerFactory.getLogger(CrawlCommand.class); + private final ConsoleView view; + private final ArticleRepository repository; + private final ScraperService scraperService; + private static final int MAX_RETRIES = 3; + private static final long RETRY_DELAY_MS = 1000; + + public CrawlCommand(ConsoleView view, ArticleRepository repository) { + this.view = view; + this.repository = repository; + this.scraperService = new ScraperService(new ArticleCrawlStrategy(), MAX_RETRIES, RETRY_DELAY_MS); + } + + @Override + public String getName() { + return "crawl"; + } + + @Override + public void execute(String[] args, List
articles) { + if (args.length < 2) { + view.printError("Usage: crawl "); + return; + } + + String url = args[1]; + logger.info("Starting crawl for URL: {}", url); + view.printInfo("Starting to crawl: " + url); + + int attempts = 0; + boolean success = false; + CrawlerException lastException = null; + + while (attempts < MAX_RETRIES && !success) { + attempts++; + try { + Article article = scraperService.scrape(url); + repository.save(article); + articles.add(article); + logger.info("Successfully crawled article: {}", article.getTitle()); + view.printSuccess("Successfully crawled: " + article.getTitle()); + success = true; + } catch (CrawlerException e) { + lastException = e; + logger.warn("Attempt {}/{} failed for URL: {}", attempts, MAX_RETRIES, url); + view.printError("Attempt " + attempts + " failed: " + e.getMessage()); + if (attempts < MAX_RETRIES) { + try { + Thread.sleep(RETRY_DELAY_MS); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + logger.error("Crawl interrupted for URL: {}", url); + view.printError("Crawl interrupted"); + return; + } + } + } + } + + if (!success) { + logger.error("Failed to crawl URL after {} attempts: {}", MAX_RETRIES, url); + view.printError("Failed to crawl after " + MAX_RETRIES + " attempts"); + if (lastException != null) { + view.printError("Last error: " + lastException.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/w11/ExitCommand.java b/w11/ExitCommand.java new file mode 100644 index 0000000..2a3c5bf --- /dev/null +++ b/w11/ExitCommand.java @@ -0,0 +1,24 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +public class ExitCommand implements Command { + private final ConsoleView view; + + public ExitCommand(ConsoleView view) { + this.view = view; + } + + @Override + public String getName() { + return "exit"; + } + + @Override + public void execute(String[] args, List
articles) { + view.printSuccess("Bye!"); + System.exit(0); + } +} \ No newline at end of file diff --git a/w11/HelpCommand.java b/w11/HelpCommand.java new file mode 100644 index 0000000..a148106 --- /dev/null +++ b/w11/HelpCommand.java @@ -0,0 +1,23 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +public class HelpCommand implements Command { + private final ConsoleView view; + + public HelpCommand(ConsoleView view) { + this.view = view; + } + + @Override + public String getName() { + return "help"; + } + + @Override + public void execute(String[] args, List
articles) { + view.printInfo("Commands: crawl , list, help, exit"); + } +} \ No newline at end of file diff --git a/w11/Main.java b/w11/Main.java new file mode 100644 index 0000000..691627b --- /dev/null +++ b/w11/Main.java @@ -0,0 +1,23 @@ +package com.example.datacollect; + +import com.example.datacollect.controller.CrawlerController; +import com.example.datacollect.model.Article; +import com.example.datacollect.repository.ArticleRepository; +import com.example.datacollect.view.ConsoleView; +import java.util.ArrayList; +import java.util.List; + +public class Main { + + public static void main(String[] args) { + ConsoleView view = new ConsoleView(); + List
articles = new ArrayList<>(); + ArticleRepository repository = new ArticleRepository(); + CrawlerController controller = new CrawlerController(view, articles, repository); + + view.printSuccess("Welcome to CLI Crawler (w11)! Type help for commands."); + while (true) { + controller.handle(view.readLine()); + } + } +} \ No newline at end of file diff --git a/w11/logback.xml b/w11/logback.xml new file mode 100644 index 0000000..1acbddf --- /dev/null +++ b/w11/logback.xml @@ -0,0 +1,26 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + logs/application.log + + logs/application-%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file