From 10584f4eb4a18ecd3ad12f880c9d720d93a69e8a Mon Sep 17 00:00:00 2001 From: gotty Date: Tue, 5 Nov 2019 14:41:26 +0000 Subject: [PATCH] [LIB-8] Console output, properties, date utils git-svn-id: https://svn.hedgecode.org/lib/snooker-score-api/trunk@173 fb0bcced-7025-49ed-a12f-f98bce993226 --- .../org/hedgecode/snooker/SnookerDateUtils.java | 71 +++++ .../org/hedgecode/snooker/SnookerScoreApp.java | 311 +++++++++++++++++---- .../org/hedgecode/snooker/SnookerScoreConsole.java | 152 ++++++++++ .../hedgecode/snooker/SnookerScoreProperties.java | 86 ++++++ src/main/resources/snooker.properties | 18 ++ 5 files changed, 590 insertions(+), 48 deletions(-) create mode 100644 src/main/java/org/hedgecode/snooker/SnookerDateUtils.java create mode 100644 src/main/java/org/hedgecode/snooker/SnookerScoreConsole.java create mode 100644 src/main/java/org/hedgecode/snooker/SnookerScoreProperties.java create mode 100644 src/main/resources/snooker.properties diff --git a/src/main/java/org/hedgecode/snooker/SnookerDateUtils.java b/src/main/java/org/hedgecode/snooker/SnookerDateUtils.java new file mode 100644 index 0000000..3fde47d --- /dev/null +++ b/src/main/java/org/hedgecode/snooker/SnookerDateUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017-2019. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.snooker; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Date and Time Utils for Matches and Events. + * + * @author Dmitry Samoshin aka gotty + */ +public final class SnookerDateUtils { + + public static final String DATE_PATTERN = "dd.MM.yyyy"; + public static final String TIME_PATTERN = "HH:mm"; + public static final String DATETIME_PATTERN = TIME_PATTERN + " " + DATE_PATTERN; + + private static final TimeZone CTZ = TimeZone.getTimeZone("CET"); + private static final TimeZone LTZ = TimeZone.getDefault(); + + private static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_PATTERN); + private static final DateFormat CET_TIME_FORMAT = new SimpleDateFormat(TIME_PATTERN); + private static final DateFormat CET_DATETIME_FORMAT = new SimpleDateFormat(DATETIME_PATTERN); + private static final DateFormat LOCAL_TIME_FORMAT = new SimpleDateFormat(TIME_PATTERN); + private static final DateFormat LOCAL_DATETIME_FORMAT = new SimpleDateFormat(DATETIME_PATTERN); + + static { + CET_TIME_FORMAT.setTimeZone(CTZ); + CET_DATETIME_FORMAT.setTimeZone(CTZ); + LOCAL_TIME_FORMAT.setTimeZone(LTZ); + LOCAL_DATETIME_FORMAT.setTimeZone(LTZ); + } + + public static String formatDate(Date date) { + return DATE_FORMAT.format(date); + } + + public static String formatTime(Date date) { + return formatTime(date, false); + } + + public static String formatTime(Date date, boolean withDate) { + return withDate ? CET_DATETIME_FORMAT.format(date) : CET_TIME_FORMAT.format(date); + } + + public static String formatLocalTime(Date date) { + return formatLocalTime(date, false); + } + + public static String formatLocalTime(Date date, boolean withDate) { + return withDate ? LOCAL_DATETIME_FORMAT.format(date) : LOCAL_TIME_FORMAT.format(date); + } + +} diff --git a/src/main/java/org/hedgecode/snooker/SnookerScoreApp.java b/src/main/java/org/hedgecode/snooker/SnookerScoreApp.java index 286c966..dbd2b9a 100644 --- a/src/main/java/org/hedgecode/snooker/SnookerScoreApp.java +++ b/src/main/java/org/hedgecode/snooker/SnookerScoreApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017. Developed by Hedgecode. + * Copyright (c) 2017-2019. Developed by Hedgecode. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,17 @@ package org.hedgecode.snooker; -import java.text.DateFormat; -import java.text.SimpleDateFormat; - import org.hedgecode.snooker.api.APIException; import org.hedgecode.snooker.api.Event; import org.hedgecode.snooker.api.Events; +import org.hedgecode.snooker.api.Match; +import org.hedgecode.snooker.api.Player; +import org.hedgecode.snooker.api.Round; +import org.hedgecode.snooker.api.Rounds; import org.hedgecode.snooker.api.Season; +import org.hedgecode.snooker.api.Seeding; +import org.hedgecode.snooker.api.Seedings; +import org.hedgecode.snooker.api.SnookerScoreAPI; /** * Snooker Score Main Application. @@ -31,68 +35,279 @@ import org.hedgecode.snooker.api.Season; */ public final class SnookerScoreApp { - private static final String EMPTY = ""; - private static final String DELIMITER = - "********************************************************************************"; - private static final String[] WELCOME = { - " Welcome to Hedgecode Snooker Score API! ", - " ----------------------------------------------- ", - " It is an API library for portal snooker.org, which contains ", - " the results of snooker competitions and other snooker information. ", - " This library provides a set of entity objects that can be used in client ", - " applications (to inform about the results of snooker), developed in Java. " - }; - private static final String CURRENT_EVENTS = " Current Snooker Events: "; - private static final String UPCOMING_EVENTS = " Upcoming Snooker Events: "; - private static final String INDENT = " "; - - private static final String DATE_FORMAT = "dd.MM.yyyy"; + private static final String ARG_PREFIX = "^[-/]"; + private static final String ARG_POSTFIX = "$"; + private static final String ARG_QUIET_REGEX = ARG_PREFIX + SnookerScoreConsole.ARG_QUIET + ARG_POSTFIX; + private static final String ARG_SERVER_REGEX = ARG_PREFIX + SnookerScoreConsole.ARG_SERVER + ARG_POSTFIX; + private static final String ARG_PORT_REGEX = ARG_PREFIX + SnookerScoreConsole.ARG_PORT + ARG_POSTFIX; + private static final String ARG_HELP_REGEX = ARG_PREFIX + SnookerScoreConsole.ARG_HELP + ARG_POSTFIX; + + private static final int INVALID_PORT = -1; + private static final int PORT_RANGE_MIN = 0; + private static final int PORT_RANGE_MAX = 65535; + private static final int PORT_RANGE_SYSTEM = 1024; + private static final String PORT_NUMBER_REGEX = "[0-9]+"; private static final int UPCOMING_COUNT = 5; + private static final int TOP_SEEDING_COUNT = 10; + + private static final String INDENT = " "; + private static final String CURRENT_EVENTS = "Current Snooker Events:"; + private static final String UPCOMING_EVENTS = "Upcoming Snooker Events:"; + private static final String EVENT_ROUNDS = "Rounds of"; + private static final String EVENT_SEEDING = "Seeding of"; public static void main(String[] args) throws APIException { - System.out.println(EMPTY); - System.out.println(DELIMITER); - for (String line : WELCOME) { - System.out.println(line); + if (isHelpMode(args)) { + + if (!isQuietMode(args)) { + printWelcome(); + } + printHelp(); + + } else if (!isQuietMode(args)) { + + printWelcome(); + + Events events = Snooker.uncachedAPI().getSeasonEvents( + Season.CURRENT_SEASON + ); + events.sortByDate(); + + printCurrentEvents(events); + printUpcomingEvents(events); + + } + + int serverPort = serverMode(args); + if (isValidPort(serverPort)) { + // todo: server mode + } + } + + private static boolean isQuietMode(String[] args) { + for (String arg : args) { + if (arg.matches(ARG_QUIET_REGEX)) { + return true; + } + } + return false; + } + + private static boolean isHelpMode(String[] args) { + for (String arg : args) { + if (arg.matches(ARG_HELP_REGEX)) { + return true; + } } + return false; + } - Events events = Snooker.uncachedAPI().getSeasonEvents( - Season.CURRENT_SEASON + + private static int serverMode(String[] args) { + boolean isServerMode = false; + int serverPort = Integer.parseInt( + SnookerScoreProperties.get("snooker.port.number") ); - events.sortByDate(); + boolean isPortArg = false; + for (String arg : args) { + if (isPortArg) { + if (arg.matches(PORT_NUMBER_REGEX)) { + serverPort = Integer.parseInt(arg); + } + isPortArg = false; + } else if (arg.matches(ARG_PORT_REGEX)) { + isPortArg = true; + } else if (arg.matches(ARG_SERVER_REGEX)) { + isServerMode = true; + } + } + return isServerMode ? serverPort : INVALID_PORT; + } + + private static boolean isValidPort(int portNumber) { + if (portNumber >= PORT_RANGE_MIN && portNumber <= PORT_RANGE_MAX) { + if (portNumber < PORT_RANGE_SYSTEM) { + SnookerScoreConsole.console( + String.format( + "%s: %s %d", + "Warning", + "Don't recommend using port numbers less than", + PORT_RANGE_SYSTEM + ) + ); + } + return true; + } + return false; + } + private static void printWelcome() { + SnookerScoreConsole.init(); + SnookerScoreConsole.welcome(); + SnookerScoreConsole.empty(); + SnookerScoreConsole.delimiter(); + } + + private static void printHelp() { + SnookerScoreConsole.empty(); + SnookerScoreConsole.help(); + SnookerScoreConsole.empty(); + } + + private static void printCurrentEvents(Events events) { Events currentEvents = events.current(); if (!currentEvents.isEmpty()) { - System.out.println(DELIMITER); - System.out.println(CURRENT_EVENTS); + SnookerScoreConsole.console( + String.format("%s%s", INDENT, CURRENT_EVENTS) + ); + for (Event currentEvent : currentEvents) { + printEvent(currentEvent, INDENT.concat(INDENT)); + } + SnookerScoreConsole.delimiter(); } - for (Event currentEvent : currentEvents) { - printEvent(currentEvent); + } + + private static void printUpcomingEvents(Events events) { + Events upcomingEvents = events.upcoming(); + if (!upcomingEvents.isEmpty()) { + SnookerScoreConsole.console( + String.format("%s%s", INDENT, UPCOMING_EVENTS) + ); + int count = 0; + for (Event upcomingEvent : upcomingEvents) { + printEvent(upcomingEvent, INDENT.concat(INDENT)); + ++count; + if (count >= UPCOMING_COUNT) break; + } + SnookerScoreConsole.delimiter(); } + } - System.out.println(DELIMITER); - System.out.println(UPCOMING_EVENTS); + private static void printEvent(Event event, String indent) { + SnookerScoreConsole.console( + String.format( + "%s%s [%s - %s] (%s, %s)", + indent, + event.name(), + SnookerDateUtils.formatDate(event.startDate()), + SnookerDateUtils.formatDate(event.endDate()), + event.country(), + event.city() + ) + ); + } - int count = 0; - Events upcomingEvents = events.upcoming(); - for (Event upcomingEvent : upcomingEvents) { - printEvent(upcomingEvent); - ++count; - if (count >= UPCOMING_COUNT) break; + private static void printPlayer(Player player) { + SnookerScoreConsole.console( + String.format( + "%s%s %s [%s] (%s)", + INDENT, + player.surnameFirst() ? player.lastName() : player.firstName(), + player.surnameFirst() ? player.firstName() : player.lastName(), + SnookerDateUtils.formatDate(player.born()), + player.nationality() + ) + ); + } + + private static void printMatch(Match match) throws APIException { + SnookerScoreAPI api = Snooker.uncachedAPI(); + Player player1 = api.getPlayer(match.player1Id()); + Player player2 = api.getPlayer(match.player2Id()); + SnookerScoreConsole.console( + String.format( + "%s[%s %s - %s] %s %s %s-%s %s %s", + INDENT, + SnookerDateUtils.formatDate(match.startDate()), + SnookerDateUtils.formatTime(match.startDate()), + SnookerDateUtils.formatTime(match.endDate()), + player1.surnameFirst() ? player1.lastName() : player1.firstName(), + player1.surnameFirst() ? player1.firstName() : player1.lastName(), + match.score1(), + match.score2(), + player2.surnameFirst() ? player2.lastName() : player2.firstName(), + player2.surnameFirst() ? player2.firstName() : player2.lastName() + ) + ); + } + + private static void printRounds(Rounds rounds, Event event) throws APIException { + if (!rounds.isEmpty()) { + rounds.sortByRound(); + if (event != null) { + SnookerScoreConsole.console( + String.format("%s%s %s:", INDENT, EVENT_ROUNDS, event.name()) + ); + } + for (Round round : rounds) { + printRound(round, event, INDENT.concat(INDENT)); + } + SnookerScoreConsole.delimiter(); + } + } + + private static void printRound(Round round, Event event, String indent) throws APIException { + if (event == null || event.getId() != round.eventId()) { + SnookerScoreAPI api = Snooker.uncachedAPI(); + Event roundEvent = api.getEvent(round.eventId()); + SnookerScoreConsole.console( + String.format( + "%s%s. %s (%s)", + indent, + round.round(), + round.roundName(), + roundEvent.name() + ) + ); + } else { + SnookerScoreConsole.console( + String.format( + "%s%s. %s", + indent, + round.round(), + round.roundName() + ) + ); + } + } + + private static void printSeedings(Seedings seedings, Event event) throws APIException { + if (!seedings.isEmpty()) { + seedings.sortBySeeding(); + if (event != null) { + SnookerScoreConsole.console( + String.format( + "%s%s %s (top %d):", + INDENT, + EVENT_SEEDING, + event.name(), + TOP_SEEDING_COUNT + ) + ); + } + int count = 0; + for (Seeding seeding : seedings) { + printSeeding(seeding, INDENT.concat(INDENT)); + ++count; + if (count >= TOP_SEEDING_COUNT) break; + } + SnookerScoreConsole.delimiter(); } - System.out.println(DELIMITER); - System.out.println(EMPTY); } - private static void printEvent(Event event) { - final DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - System.out.println( - INDENT + event.name() - + " [" + dateFormat.format(event.startDate()) - + " - " + dateFormat.format(event.endDate()) + "]" - + " (" + event.country() + ", " + event.city() + ")" + private static void printSeeding(Seeding seeding, String indent) throws APIException { + SnookerScoreAPI api = Snooker.uncachedAPI(); + Player player = api.getPlayer(seeding.playerId()); + SnookerScoreConsole.console( + String.format( + "%s%s. %s %s", + indent, + seeding.seeding(), + player.surnameFirst() ? player.lastName() : player.firstName(), + player.surnameFirst() ? player.firstName() : player.lastName() + ) ); } diff --git a/src/main/java/org/hedgecode/snooker/SnookerScoreConsole.java b/src/main/java/org/hedgecode/snooker/SnookerScoreConsole.java new file mode 100644 index 0000000..bf5d97c --- /dev/null +++ b/src/main/java/org/hedgecode/snooker/SnookerScoreConsole.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017-2019. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.snooker; + +import java.util.Calendar; + +/** + * Snooker Score utility class for working with console. + * + * @author Dmitry Samoshin aka gotty + */ +public final class SnookerScoreConsole { + + private static final String[] ASCII_LOGO = { + " _______ _ _ ", + " | | _|_ _| |___ ___ ___ ___ _| |___ ", + " | | -_| . | . | -_| _| . | . | -_| ", + " | |___|___|_ |___|___|___|___|___| ", + " |___|___| _ |___| ", + " ___ ___ ___ ___| |_ ___ ___ ___ ___ ___ ___ ___ ", + " |_ -| | . | . | '_| -_| _| |_ -| _| . | _| -_| ", + " |___|_|_|___|___|_,_|___|_| |___|___|___|_| |___| ", + " _____ _____ _ ", + " | _ | _ |_| ", + " | | __| | ", + " |__|__|__| |_| " + }; + + private static final String COPYRIGHT = "Copyright (c) Hedgecode"; + + private static final String DELIMITER = "*"; + + private static final String[] WELCOME = { + " Welcome to Hedgecode Snooker Score API! ", + " ----------------------------------------------- ", + " It is an API library for portal snooker.org, which contains ", + " the results of snooker competitions and other snooker information. ", + " This library provides a set of entity objects that can be used in client ", + " applications (to inform about the results of snooker), developed in Java. " + }; + + public static final String ARG_QUIET = "quiet"; + public static final String ARG_SERVER = "server"; + public static final String ARG_PORT = "port"; + public static final String ARG_HELP = "help"; + + private SnookerScoreConsole() { + } + + public static void console(String message) { + System.out.println( + message == null ? "" : message + ); + } + + public static void empty() { + console(null); + } + + public static void delimiter() { + console( + String.format( + "%" + length() + "s", + DELIMITER + ).replace(" ", DELIMITER) + ); + } + + public static void init() { + asciiLogo(); + empty(); + copyright(); + version(); + empty(); + } + + public static void welcome() { + for (String line : WELCOME) { + console(line); + } + } + + public static void help() { + console( + String.format( + "Usage: java -jar %s-%s.jar -[%s|%s|%s XXXX|%s]", + SnookerScoreProperties.get("snooker.name"), + SnookerScoreProperties.get("snooker.version"), + ARG_QUIET, + ARG_SERVER, + ARG_PORT, + ARG_HELP + ) + ); + } + + private static void asciiLogo() { + for (String line : ASCII_LOGO) { + console(line); + } + } + + private static void copyright() { + int inceptionYear = Integer.parseInt( + SnookerScoreProperties.get("snooker.inception.year") + ); + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + String copyright = currentYear > inceptionYear + ? String.format("%s-%s %s", inceptionYear, currentYear, COPYRIGHT) + : String.format("%s %s", currentYear, COPYRIGHT); + console( + alignCenter(copyright) + ); + } + + private static void version() { + console( + alignCenter( + String.format( + "v. %s", SnookerScoreProperties.get("snooker.version") + ) + ) + ); + } + + private static String alignCenter(String message) { + int indent = (length() + message.length()) / 2; + return String.format( + "%" + indent + "s", + message + ); + } + + private static int length() { + return ASCII_LOGO[0].length(); + } + +} diff --git a/src/main/java/org/hedgecode/snooker/SnookerScoreProperties.java b/src/main/java/org/hedgecode/snooker/SnookerScoreProperties.java new file mode 100644 index 0000000..0c8bc7e --- /dev/null +++ b/src/main/java/org/hedgecode/snooker/SnookerScoreProperties.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017-2019. Developed by Hedgecode. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.hedgecode.snooker; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * Snooker Score properties holder. + * + * @author Dmitry Samoshin aka gotty + */ +public final class SnookerScoreProperties { + + /** Properties file. */ + private static final String PROPERTIES_FILE = "snooker.properties"; + + /** Properties. */ + private static final Properties PROPERTIES; + + /** + * Static properties initialization. + */ + static { + PROPERTIES = new Properties(); + readProperties(PROPERTIES_FILE, PROPERTIES, true); + } + + /** + * @param propsFile Properties file name. + * @param props Properties. + * @param throwExc Flag indicating whether to throw an exception or not. + */ + public static void readProperties(String propsFile, Properties props, boolean throwExc) { + try (InputStream is = SnookerScoreProperties.class.getClassLoader().getResourceAsStream(propsFile)) { + if (is == null) { + if (throwExc) + throw new RuntimeException("Failed to find properties file: " + propsFile); + else + return; + } + + props.load(is); + } + catch (IOException e) { + throw new RuntimeException("Failed to read properties file: " + propsFile, e); + } + } + + /** + * Empty string for not found properties. + */ + private static final String EMPTY = ""; + + /** + * Gets property value. + * + * @param key Property key. + * @return Property value (possibly empty string, but never {@code null}). + */ + public static String get(String key) { + return PROPERTIES.getProperty(key, EMPTY); + } + + /** + * Private constructor. + */ + private SnookerScoreProperties() { + } + +} diff --git a/src/main/resources/snooker.properties b/src/main/resources/snooker.properties new file mode 100644 index 0000000..7de719c --- /dev/null +++ b/src/main/resources/snooker.properties @@ -0,0 +1,18 @@ +# Copyright (c) 2017-2019. Developed by Hedgecode. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +snooker.name=snooker-score-api +snooker.version=0.2-SNAPSHOT +snooker.inception.year=2017 +snooker.port.number=1470 -- 2.10.0