[LIB-13] Lazy scanners init, scan by URL and rename API functions
authorgotty <gotty@hedgecode.org>
Wed, 15 Jan 2020 19:51:09 +0000 (22:51 +0300)
committergotty <gotty@hedgecode.org>
Wed, 15 Jan 2020 19:51:09 +0000 (22:51 +0300)
src/main/java/org/hedgecode/chess/scanner/ChessHogScanner.java
src/main/java/org/hedgecode/chess/scanner/ChessHogScannerConsole.java
src/main/java/org/hedgecode/chess/scanner/ChessHogScannerConstants.java
src/main/java/org/hedgecode/chess/scanner/ChessHogScannerProperties.java
src/main/java/org/hedgecode/chess/scanner/Scanner.java
src/main/java/org/hedgecode/chess/scanner/ScannerType.java
src/main/java/org/hedgecode/chess/scanner/portal/ChessBombScanner.java
src/main/java/org/hedgecode/chess/scanner/portal/ChessGamesScanner.java
src/main/java/org/hedgecode/chess/scanner/portal/LiChessScanner.java
src/main/resources/scanner.properties

index 9b90990..fdb5036 100644 (file)
 
 package org.hedgecode.chess.scanner;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
+import org.hedgecode.chess.scanner.entity.PGNGame;
 import org.hedgecode.chess.scanner.portal.ChessBombScanner;
 import org.hedgecode.chess.scanner.portal.ChessGamesScanner;
 import org.hedgecode.chess.scanner.portal.LiChessScanner;
@@ -30,9 +35,9 @@ import org.hedgecode.chess.scanner.portal.LiChessScanner;
  */
 public final class ChessHogScanner {
 
-    private static ChessHogScanner _instance;
+    private static ChessHogScanner singleton;
 
-    private final Map<ScannerType, Scanner> SCANNERS = new HashMap<ScannerType, Scanner>() {
+    private final Map<ScannerType, Scanner> scanners = new HashMap<ScannerType, Scanner>() {
         {
             put( ScannerType.CHESSGAMES, new ChessGamesScanner() );
             put( ScannerType.LICHESS,    new LiChessScanner()    );
@@ -40,36 +45,81 @@ public final class ChessHogScanner {
         }
     };
 
-    public static Scanner get(ScannerType type) {
-        return getInstance().scanner(type);
+    private final Set<ScannerType> initScanners = new HashSet<>();
+
+    /**
+     * Get Scanner by {@code ScannerType}.
+     *
+     * @param type Scanner type (binding to specific chess portal).
+     * @return Implementation of {@code Scanner} for specific portal.
+     */
+    public static Scanner scanner(ScannerType type) {
+        return getStore().getScanner(type);
+    }
+
+    /**
+     * Scan PGN game by URL (for all scanner types).
+     *
+     * @param url URL string for scan.
+     * @return PGN game.
+     * @throws ChessHogScannerException Incorrect URL or unknown chess portal.
+     */
+    public static PGNGame scan(String url) throws ChessHogScannerException {
+        String hostName;
+        try {
+            hostName = new URL(url).getHost();
+        } catch (MalformedURLException cause) {
+            throw new ChessHogScannerException(
+                    String.format("Incorrect  URL: %s", url), cause
+            );
+        }
+        ScannerType type = ScannerType.byHost(hostName);
+        if (type == null) {
+            throw new ChessHogScannerException(
+                    String.format("Host %s is not among the known for the scanner", hostName)
+            );
+        }
+        return scanner(type).scanUrl(url);
     }
 
     private void init() {
+        for (ScannerType type : scanners.keySet()) {
+            init(type);
+        }
+    }
+
+    private void init(ScannerType type) {
+        Scanner scanner = scanners.get(type);
         try {
-            for (Scanner scanner : SCANNERS.values()) {
-                if (scanner instanceof Initiable) {
-                    Initiable initiableScanner = (Initiable) scanner;
-                    initiableScanner.init();
-                }
+            if (scanner instanceof Initiable) {
+                Initiable initiableScanner = (Initiable) scanner;
+                initiableScanner.init();
             }
+            initScanners.add(type);
         } catch (ChessHogScannerException e) {
             throw new RuntimeException(e);
         }
     }
 
-    private Scanner scanner(ScannerType type) {
-        return SCANNERS.get(type);
+
+    private Scanner getScanner(ScannerType type) {
+        if (!initScanners.contains(type)) {
+            init(type);
+        }
+        return scanners.get(type);
     }
 
     private ChessHogScanner() {
+        if (!ChessHogScannerProperties.is("scanner.lazy.init")) {
+            init();
+        }
     }
 
-    private static ChessHogScanner getInstance() {
-        if (_instance == null) {
-            _instance = new ChessHogScanner();
-            _instance.init();
+    private static ChessHogScanner getStore() {
+        if (singleton == null) {
+            singleton = new ChessHogScanner();
         }
-        return _instance;
+        return singleton;
     }
 
 }
index b3becd9..4b824fb 100644 (file)
@@ -78,9 +78,7 @@ public class ChessHogScannerConsole {
     }
 
     private static void copyright() {
-        int inceptionYear = Integer.parseInt(
-                ChessHogScannerProperties.get("scanner.inception.year")
-        );
+        int inceptionYear = ChessHogScannerProperties.getInt("scanner.inception.year");
         int currentYear = Calendar.getInstance().get(Calendar.YEAR);
         String copyright = currentYear > inceptionYear
                 ? String.format("%s-%s %s", inceptionYear, currentYear, COPYRIGHT)
index 651a3e4..50eb391 100644 (file)
@@ -30,11 +30,17 @@ public final class ChessHogScannerConstants {
 
     public static final String CRLF = System.getProperty("line.separator");
 
-    public static final String PORTAL_CHESSGAMES = "chessgames";
-    public static final String PORTAL_LICHESS = "lichess";
-    public static final String PORTAL_CHESSBOMB = "chessbomb";
-    public static final String PORTAL_CHESS24 = "chess24";
-    public static final String PORTAL_CHESSCOM = "chesscom";
+    public static final String TYPE_CHESSGAMES = "chessgames";
+    public static final String TYPE_LICHESS = "lichess";
+    public static final String TYPE_CHESSBOMB = "chessbomb";
+    public static final String TYPE_CHESS24 = "chess24";
+    public static final String TYPE_CHESSCOM = "chesscom";
+
+    public static final String DOMAIN_CHESSGAMES = "chessgames.com";
+    public static final String DOMAIN_LICHESS = "lichess.org";
+    public static final String DOMAIN_CHESSBOMB = "www.chessbomb.com";
+    public static final String DOMAIN_CHESS24 = "chess24.com";
+    public static final String DOMAIN_CHESSCOM = "chess.com";
 
     public static final String PROXY_UNDEFINED = "undefined";
     public static final String PROXY_HTTP = "http";
@@ -42,7 +48,7 @@ public final class ChessHogScannerConstants {
 
     private ChessHogScannerConstants() {
         throw new AssertionError(
-                String.format("No %s instances!", ChessHogScannerConstants.class.getName())
+                String.format("No %s instances!", getClass().getName())
         );
     }
 
index e7565bc..fdead40 100644 (file)
@@ -73,7 +73,7 @@ public class ChessHogScannerProperties {
     private static final String EMPTY = "";
 
     /**
-     * Gets property value.
+     * Gets string property value.
      *
      * @param key Property key.
      * @return Property value (possibly empty string, but never {@code null}).
@@ -83,6 +83,35 @@ public class ChessHogScannerProperties {
     }
 
     /**
+     * Gets boolean property value.
+     *
+     * @param key Property key.
+     * @return Property value ({@code false} by default).
+     */
+    public static boolean is(String key) {
+        return Boolean.parseBoolean(
+                PROPERTIES.getProperty(key, Boolean.FALSE.toString())
+        );
+    }
+
+    /**
+     * Zero integer for not found properties.
+     */
+    private static final String ZERO = "0";
+
+    /**
+     * Gets integer property value.
+     *
+     * @param key Property key.
+     * @return Property value ({@code 0} by default).
+     */
+    public static int getInt(String key) {
+        return Integer.parseInt(
+                PROPERTIES.getProperty(key, ZERO)
+        );
+    }
+
+    /**
      * Private constructor.
      */
     private ChessHogScannerProperties() {
index 0192f2b..2c6095a 100644 (file)
@@ -26,12 +26,14 @@ import org.hedgecode.chess.scanner.entity.PGNTournament;
  */
 public interface Scanner {
 
-    PGNTournament getTournament(String tournamentId) throws ChessHogScannerException;
+    PGNTournament scanTournament(String tournamentId) throws ChessHogScannerException;
 
     PGNTournament findTournament(String tournamentName) throws ChessHogScannerException;
 
-    PGNGame getGame(String gameId) throws ChessHogScannerException;
+    PGNGame scanGame(String gameId) throws ChessHogScannerException;
 
-    PGNGame getGame(String gameId, String tournamentId) throws ChessHogScannerException;
+    PGNGame scanGame(String gameId, String tournamentId) throws ChessHogScannerException;
+
+    PGNGame scanUrl(String gameUrl) throws ChessHogScannerException;
 
 }
index f0a6495..306c316 100644 (file)
@@ -16,6 +16,8 @@
 
 package org.hedgecode.chess.scanner;
 
+import static org.hedgecode.chess.scanner.ChessHogScannerConstants.*;
+
 /**
  * ScannerType
  *
@@ -23,22 +25,28 @@ package org.hedgecode.chess.scanner;
  */
 public enum ScannerType {
 
-    CHESSGAMES (ChessHogScannerConstants.PORTAL_CHESSGAMES),
-    LICHESS    (ChessHogScannerConstants.PORTAL_LICHESS),
-    CHESSBOMB  (ChessHogScannerConstants.PORTAL_CHESSBOMB),
-    CHESS24    (ChessHogScannerConstants.PORTAL_CHESS24),
-    CHESSCOM   (ChessHogScannerConstants.PORTAL_CHESSCOM);
+    CHESSGAMES ( TYPE_CHESSGAMES, DOMAIN_CHESSGAMES ),
+    LICHESS    ( TYPE_LICHESS,    DOMAIN_LICHESS    ),
+    CHESSBOMB  ( TYPE_CHESSBOMB,  DOMAIN_CHESSBOMB  ),
+    CHESS24    ( TYPE_CHESS24,    DOMAIN_CHESS24    ),
+    CHESSCOM   ( TYPE_CHESSCOM,   DOMAIN_CHESSCOM   );
 
     private String type;
+    private String domain;
 
-    ScannerType(String type) {
+    ScannerType(String type, String domain) {
         this.type = type;
+        this.domain = domain;
     }
 
     public String type() {
         return type;
     }
 
+    public String domain() {
+        return domain;
+    }
+
     public static ScannerType byType(String type) {
         for (ScannerType scannerType : ScannerType.values()) {
             if (scannerType.type.equals(type))
@@ -47,4 +55,14 @@ public enum ScannerType {
         return null;
     }
 
+    public static ScannerType byHost(String host) {
+        if (host != null) {
+            for (ScannerType scannerType : ScannerType.values()) {
+                if (host.contains(scannerType.domain))
+                    return scannerType;
+            }
+        }
+        return null;
+    }
+
 }
index d8b6ed0..7b19256 100644 (file)
@@ -41,7 +41,7 @@ public class ChessBombScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNTournament getTournament(String tournamentId) throws ChessHogScannerException {
+    public PGNTournament scanTournament(String tournamentId) throws ChessHogScannerException {
         String decodeTournament = decodeUrlByRegex(
                 assignUrl(tournamentId, null),
                 getSettings().getTournamentGamesUrlRegex()
@@ -55,7 +55,7 @@ public class ChessBombScanner extends AbstractSettingsScanner {
 
         for (String gameId : tournamentFormat.gameUrls()) {
             tournament.addGame(
-                    getGame(gameId, tournamentId)
+                    scanGame(gameId, tournamentId)
             );
         }
 
@@ -74,19 +74,19 @@ public class ChessBombScanner extends AbstractSettingsScanner {
         String tournamentId = arenaFormat.findTournament(tournamentName);
 
         return tournamentId != null
-                ? getTournament(tournamentId)
+                ? scanTournament(tournamentId)
                 : null;
     }
 
     @Override
-    public PGNGame getGame(String gameId) throws ChessHogScannerException {
+    public PGNGame scanGame(String gameId) throws ChessHogScannerException {
         throw new ChessHogScannerException(
                 "ChessBomb does not support searching game without a tournament name!"
         );
     }
 
     @Override
-    public PGNGame getGame(String gameId, String tournamentId) throws ChessHogScannerException {
+    public PGNGame scanGame(String gameId, String tournamentId) throws ChessHogScannerException {
         String decodeGame = decodeUrlByRegex(
                 assignUrl(gameId, tournamentId, true),
                 getSettings().getGameUrlRegex()
@@ -100,6 +100,11 @@ public class ChessBombScanner extends AbstractSettingsScanner {
         );
     }
 
+    @Override
+    public PGNGame scanUrl(String gameUrl) throws ChessHogScannerException {
+        return null;
+    }
+
     private String decodeUrlByRegex(String url, String regex) throws ChessHogScannerException {
         String encodeString = match(
                 url,
index 6346929..7658ba1 100644 (file)
@@ -39,7 +39,7 @@ public class ChessGamesScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNTournament getTournament(String tournamentId) throws ChessHogScannerException {
+    public PGNTournament scanTournament(String tournamentId) throws ChessHogScannerException {
         PGNTournament tournament = new PGNTournament(tournamentId);
         assignTournamentGames(tournament);
         return tournament;
@@ -70,7 +70,7 @@ public class ChessGamesScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNGame getGame(String gameId) throws ChessHogScannerException {
+    public PGNGame scanGame(String gameId) throws ChessHogScannerException {
         String pgn = request(
                 assignUrl(gameId)
         );
@@ -80,8 +80,13 @@ public class ChessGamesScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNGame getGame(String gameId, String tournamentId) throws ChessHogScannerException {
-        return getGame(gameId);
+    public PGNGame scanGame(String gameId, String tournamentId) throws ChessHogScannerException {
+        return scanGame(gameId);
+    }
+
+    @Override
+    public PGNGame scanUrl(String gameUrl) throws ChessHogScannerException {
+        return null;
     }
 
     private void assignTournamentGames(PGNTournament tournament) throws ChessHogScannerException {
@@ -106,7 +111,7 @@ public class ChessGamesScanner extends AbstractSettingsScanner {
 
         for (String gameId : gamesId) {
             tournament.addGame(
-                    getGame(gameId)
+                    scanGame(gameId)
             );
         }
     }
index 1449392..134180e 100644 (file)
@@ -43,7 +43,7 @@ public class LiChessScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNTournament getTournament(String tournamentId) throws ChessHogScannerException {
+    public PGNTournament scanTournament(String tournamentId) throws ChessHogScannerException {
         PGNTournament tournament = new PGNTournament(tournamentId);
         assignTournamentGames(tournament);
         return tournament;
@@ -57,7 +57,7 @@ public class LiChessScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNGame getGame(String gameId) throws ChessHogScannerException {
+    public PGNGame scanGame(String gameId) throws ChessHogScannerException {
         String pgn = request(
                 assignUrl(gameId)
         );
@@ -67,8 +67,13 @@ public class LiChessScanner extends AbstractSettingsScanner {
     }
 
     @Override
-    public PGNGame getGame(String gameId, String tournamentId) throws ChessHogScannerException {
-        return getGame(gameId);
+    public PGNGame scanGame(String gameId, String tournamentId) throws ChessHogScannerException {
+        return scanGame(gameId);
+    }
+
+    @Override
+    public PGNGame scanUrl(String gameUrl) throws ChessHogScannerException {
+        return null;
     }
 
     private void assignTournamentGames(PGNTournament tournament) throws ChessHogScannerException {
index ea03876..bb0415e 100644 (file)
@@ -16,6 +16,8 @@ scanner.name=chesshog-scanner
 scanner.version=0.1-SNAPSHOT
 scanner.inception.year=2019
 
+scanner.lazy.init=true
+
 scanner.use.proxy=false
 scanner.proxy.server=
 scanner.proxy.auth=