diff --git a/task01/src/com/example/task01/Task01Main.java b/task01/src/com/example/task01/Task01Main.java index 9973557d..7ba6d38e 100644 --- a/task01/src/com/example/task01/Task01Main.java +++ b/task01/src/com/example/task01/Task01Main.java @@ -1,7 +1,107 @@ package com.example.task01; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.HashMap; + +class Logger { + + public enum Level{ + DEBUG, + INFO, + WARNING, + ERROR + } + + private final String name; + private static final Map loggers = new HashMap<>(); + private Level level = Level.DEBUG; + + private Logger(String name){ + this.name = name; + } + + public String getName(){ + return name; + } + + public static Logger getLogger(String nickName){ + if (!loggers.containsKey(nickName)){ + loggers.put(nickName, new Logger(nickName)); + } + return loggers.get(nickName); + } + + public void setLevel(Level level){ + this.level = level; + } + + public Level getLevel(){ + return level; + } + + private String formatTimestamp(){ + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd"); + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); + return dateFormat.format(new Date()) + " " + timeFormat.format(new Date()); + } + + public void log(Level level, String message){ + if (level.ordinal() >= this.level.ordinal()){ + System.out.println(String.format("[%s] %s %s - %s", level, formatTimestamp(), name, message)); + } + } + + public void log (Level level, String format, Object... args){ + if (level.ordinal() >= this.level.ordinal()){ + String message = String.format(format, args); + System.out.println(String.format("[%s] %s %s - %s", level, formatTimestamp(), name, message)); + } + } + + public void debug(String message){ + log(Level.DEBUG, message); + } + + public void debug(String format, Object... args){ + log(Level.DEBUG, format, args); + } + + public void info(String message){ + log(Level.INFO, message); + } + + public void info(String format, Object... args){ + log(Level.INFO, format, args); + } + + public void warning(String message){ + log(Level.WARNING, message); + } + + public void warning(String format, Object... args){ + log(Level.WARNING, format, args); + } + + public void error(String message){ + log(Level.ERROR, message); + } + + public void error(String format, Object... args){ + log(Level.ERROR, format, args); + } + + + +} public class Task01Main { public static void main(String[] args) { + Logger logger = Logger.getLogger("myLogger"); + logger.setLevel(Logger.Level.WARNING); + logger.debug("Это сообщение не появится"); + logger.warning("Предупреждение: что-то пошло не так"); + logger.error("Ошибка: %s", "критическая ситуация"); } } diff --git a/task02/src/com/example/task02/DiscountBill.java b/task02/src/com/example/task02/DiscountBill.java new file mode 100644 index 00000000..d6002787 --- /dev/null +++ b/task02/src/com/example/task02/DiscountBill.java @@ -0,0 +1,32 @@ +package com.example.task02; + +public class DiscountBill extends Bill{ + private double discountPercentage; + + public DiscountBill(double discountPercentage){ + setDiscountPercentage(discountPercentage); + } + + public void setDiscountPercentage(double discountPercentage){ + if (discountPercentage < 0 || discountPercentage > 100){ + throw new IllegalArgumentException("Скидка должна быть в диапазона от 1 до 100"); + } + this.discountPercentage = discountPercentage; + } + + public double getDiscountPercentage(){ + return discountPercentage; + } + + public long getDiscountAbsolute(){ + long originalPrice = super.getPrice(); + return Math.round(originalPrice * discountPercentage / 100); + } + + public long getPrice(){ + long originalPrice = super.getPrice(); + long discount = getDiscountAbsolute(); + return originalPrice - discount; + } + +} diff --git a/task02/src/com/example/task02/Task02Main.java b/task02/src/com/example/task02/Task02Main.java index e589f2d3..b5d804a5 100644 --- a/task02/src/com/example/task02/Task02Main.java +++ b/task02/src/com/example/task02/Task02Main.java @@ -19,3 +19,5 @@ public static void main(String[] args) { System.out.println(bill); } } + + diff --git a/task03/README.md b/task03/README.md index 9943bddb..3644cf74 100644 --- a/task03/README.md +++ b/task03/README.md @@ -13,4 +13,5 @@ Этапы выполнения задания: * Реализовать класс `Hours`, который определяет интервал в часах * Добавить методы по переводу интервалов из одних единиц в другие в классе `TimeUnitUtils` -* Добавить новый метод в интерфейс `TimeUnit` - `long getHours()`, возвращающий количество часов в интервале. Реализовать новый метод для существующих классов интервалов и добавить новый класс `Hours`. +* Добавить новый метод в интерфейс `TimeUnit` - `long getHours()`, возвращающий количество часов в интервале. +* Реализовать новый метод для существующих классов интервалов и добавить новый класс `Hours`. diff --git a/task03/src/com/example/task03/Hours.java b/task03/src/com/example/task03/Hours.java new file mode 100644 index 00000000..3b0ab8a9 --- /dev/null +++ b/task03/src/com/example/task03/Hours.java @@ -0,0 +1,18 @@ +package com.example.task03; + +public class Hours implements TimeUnit{ + + private final long amount; + + public Hours(long amount) { + this.amount = amount; + } + + public long toMillis() { return amount * 60 * 60 * 1000; } + + public long toSeconds() {return amount * 60 * 60; } + + public long toMinutes() {return amount * 60; } + + public long toHours() { return amount; } +} diff --git a/task03/src/com/example/task03/Milliseconds.java b/task03/src/com/example/task03/Milliseconds.java index 5115bc7d..1df5942a 100644 --- a/task03/src/com/example/task03/Milliseconds.java +++ b/task03/src/com/example/task03/Milliseconds.java @@ -18,11 +18,14 @@ public long toMillis() { @Override public long toSeconds() { - return amount / 1000; + return Math.round((float)amount / 1000); } @Override public long toMinutes() { - return amount / 1000 * 60; + return Math.round((float)amount / (1000 * 60)); } + + @Override + public long toHours() { return Math.round((float)amount / (1000 * 60 * 60)); } } diff --git a/task03/src/com/example/task03/Minutes.java b/task03/src/com/example/task03/Minutes.java index d6fa0594..4fe5e47e 100644 --- a/task03/src/com/example/task03/Minutes.java +++ b/task03/src/com/example/task03/Minutes.java @@ -2,26 +2,31 @@ public class Minutes implements TimeUnit { + private final long amount; + public Minutes(long amount) { - // TODO: реализовать - throw new UnsupportedOperationException(); + this.amount = amount; } @Override public long toMillis() { - // TODO: реализовать - throw new UnsupportedOperationException(); + return amount * 1000 * 60; } @Override public long toSeconds() { - // TODO: реализовать - throw new UnsupportedOperationException(); + return amount * 60; } @Override public long toMinutes() { - // TODO: реализовать - throw new UnsupportedOperationException(); + return amount; + } + + @Override + public long toHours() { + return Math.round((float)amount / 60); } + + } diff --git a/task03/src/com/example/task03/Seconds.java b/task03/src/com/example/task03/Seconds.java index ce6bc213..364bf2fb 100644 --- a/task03/src/com/example/task03/Seconds.java +++ b/task03/src/com/example/task03/Seconds.java @@ -22,7 +22,8 @@ public long toSeconds() { } @Override - public long toMinutes() { - return Math.round(amount / 60); - } + public long toMinutes() { return Math.round((float)amount / 60); } + + @Override + public long toHours() { return Math.round((float) amount /(60 *60)); } } diff --git a/task03/src/com/example/task03/Task03Main.java b/task03/src/com/example/task03/Task03Main.java index ff0f14b0..480631b8 100644 --- a/task03/src/com/example/task03/Task03Main.java +++ b/task03/src/com/example/task03/Task03Main.java @@ -12,3 +12,4 @@ private static void printTimeUnit(TimeUnit unit) { System.out.println(String.format("Minutes: %d", unit.toMinutes())); } } + diff --git a/task03/src/com/example/task03/TimeUnit.java b/task03/src/com/example/task03/TimeUnit.java index 3b123fb8..3bf1089f 100644 --- a/task03/src/com/example/task03/TimeUnit.java +++ b/task03/src/com/example/task03/TimeUnit.java @@ -28,4 +28,5 @@ public interface TimeUnit { */ long toMinutes(); + long toHours(); } diff --git a/task03/src/com/example/task03/TimeUnitUtils.java b/task03/src/com/example/task03/TimeUnitUtils.java index 790f8850..7b132197 100644 --- a/task03/src/com/example/task03/TimeUnitUtils.java +++ b/task03/src/com/example/task03/TimeUnitUtils.java @@ -24,4 +24,8 @@ public static Milliseconds toMillis(Seconds seconds) { public static Seconds toSeconds(Milliseconds millis) { return new Seconds(millis.toSeconds()); } + + public static Hours toHours(TimeUnit unit) { + return new Hours(unit.toHours()); + } } diff --git a/task04/README.md b/task04/README.md index 2ab3302c..382436f8 100644 --- a/task04/README.md +++ b/task04/README.md @@ -1,16 +1,22 @@ # Задание 04 - Продвинутый логгер В предыдущем задании был реализован класс, логирующий сообщения в определенном формате в консоль. -Необходимо модифицировать данный класс таким образом, чтобы можно было позволить логгировать не только в консоль, но и в файл, память или что-либо еще. +Необходимо модифицировать данный класс таким образом, чтобы можно было позволить логгировать не только +в консоль, но и в файл, память или что-либо еще. -Для реализации данной задачи потребуется ввести дополнительный уровень абстракции - интерфейс `MessageHandler`, который по своей логике будет заниматься конечной обработкой сообщений логгера. +Для реализации данной задачи потребуется ввести дополнительный уровень абстракции - интерфейс `MessageHandler`, +который по своей логике будет заниматься конечной обработкой сообщений логгера. В качестве конечных обработчиков сообщений нужно реализовать следующие: * `ConsoleHandler` - обработчик, выводящий сообщения в консоль * `FileHandler` - обработчик, выводящий сообщения в файл -* `RotationFileHandler` - обработчик, выводящий сообщения в файл с определенной ротацией - например, для каждого часа создается свой файл. Для данного обработчика нужно иметь возможность выставлять интервал ротации (например, с помощью java.time.temporal.ChronoUnit, либо другим удобным способом). -* `MemoryHandler` - обработчик - прокси, который может аккумулировать сообщения в памяти и при необходимости (явном вызове метода или при достижении определенного объема) отправлять их в проксируемый обработчик. +* `RotationFileHandler` - обработчик, выводящий сообщения в файл с определенной ротацией - например, для каждого +* часа создается свой файл. Для данного обработчика нужно иметь возможность выставлять интервал ротации +* (например, с помощью java.time.temporal.ChronoUnit, либо другим удобным способом). +* `MemoryHandler` - обработчик - прокси, который может аккумулировать сообщения в памяти и при необходимости +* (явном вызове метода или при достижении определенного объема) отправлять их в проксируемый обработчик. - Например, с помощью данного класса мы должны уметь отправлять сообщения в консоль (или файл), но только определенными "порциями". + Например, с помощью данного класса мы должны уметь отправлять сообщения в консоль (или файл), но только +* определенными "порциями". Логгер должен иметь возможность использовать несколько обработчиков одновременно. diff --git a/task04/src/com/example/task04/ConsoleHandler.java b/task04/src/com/example/task04/ConsoleHandler.java new file mode 100644 index 00000000..eee19168 --- /dev/null +++ b/task04/src/com/example/task04/ConsoleHandler.java @@ -0,0 +1,14 @@ +package com.example.task04; + +public class ConsoleHandler implements MessageHandler{ + + @Override + public void publish(String formattedMessage) { + System.out.println(formattedMessage); + } + + @Override + public void close() { + + } +} diff --git a/task04/src/com/example/task04/FileHandler.java b/task04/src/com/example/task04/FileHandler.java new file mode 100644 index 00000000..aa26d45d --- /dev/null +++ b/task04/src/com/example/task04/FileHandler.java @@ -0,0 +1,33 @@ +package com.example.task04; +import java.io.*; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +public class FileHandler implements MessageHandler{ + + private final BufferedWriter writer ; + + public FileHandler(String fileName) throws IOException { + if (fileName == null || fileName.trim().isEmpty()) { + throw new IllegalArgumentException("Имя файла не может быть пустым"); + } + this.writer = new BufferedWriter(new FileWriter(fileName, true)); + } + + @Override + public void publish(String formattedMessage) throws IOException { + if (formattedMessage == null) { + throw new IllegalArgumentException("Сообщение не может быть null"); + } + writer.write(formattedMessage); + writer.newLine(); + writer.flush(); + } + + @Override + public void close() throws IOException{ + writer.close(); + } + +} diff --git a/task04/src/com/example/task04/Logger.java b/task04/src/com/example/task04/Logger.java new file mode 100644 index 00000000..b709630f --- /dev/null +++ b/task04/src/com/example/task04/Logger.java @@ -0,0 +1,108 @@ +package com.example.task04; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +public class Logger { + + + + public enum Level { + DEBUG, INFO, WARNING, ERROR + } + + private final String name; + private static final Map loggers = new HashMap<>(); + private static final ReentrantLock lock = new ReentrantLock(); + private Level level = Level.DEBUG; + private MessageHandler handler; // Добавлен обработчик + + private Logger(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public static Logger getLogger(String nickName) { + lock.lock(); + try { + Logger logger = loggers.get(nickName); + if (logger == null) { + logger = new Logger(nickName); + loggers.put(nickName, logger); + } + return logger; + } finally { + lock.unlock(); + } + } + + public void setLevel(Level level) { + this.level = level; + } + + public Level getLevel() { + return level; + } + + // Установщик обработчика + public void setHandler(MessageHandler handler) { + this.handler = handler; + } + + private String formatTimestamp() { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); + return dateFormat.format(new Date()); + } + + private void logInternal(Level level, String message) throws IOException { + if (level.ordinal() >= this.level.ordinal()) { + String formatted = String.format("[%s] %s %s - %s", + level, formatTimestamp(), name, message); + + if (handler != null) { + handler.publish(formatted); + } else { + System.out.println(formatted); // Резерв + } + } + } + + public void log(Level level, String message) { + try { + logInternal(level, message); + } catch (IOException e) { + System.err.println("Ошибка записи лога: " + e.getMessage()); + } + } + + public void log(Level level, String format, Object... args) { + try { + String message = String.format(format, args); + logInternal(level, message); + } catch (IOException e) { + System.err.println("Ошибка записи лога: " + e.getMessage()); + } + } + + public MessageHandler getHandler() { + return this.handler; + } + + + // Методы-обёртки (без изменений) + public void debug(String message) { log(Level.DEBUG, message); } + public void debug(String format, Object... args) { log(Level.DEBUG, format, args); } + public void info(String message) { log(Level.INFO, message); } + public void info(String format, Object... args) { log(Level.INFO, format, args); } + public void warning(String message) { log(Level.WARNING, message); } + public void warning(String format, Object... args) { log(Level.WARNING, format, args); } + public void error(String message) { log(Level.ERROR, message); } + public void error(String format, Object... args) { log(Level.ERROR, format, args); } +} diff --git a/task04/src/com/example/task04/MessageHandler.java b/task04/src/com/example/task04/MessageHandler.java new file mode 100644 index 00000000..43e45999 --- /dev/null +++ b/task04/src/com/example/task04/MessageHandler.java @@ -0,0 +1,10 @@ +package com.example.task04; + +import java.io.IOException; + +public interface MessageHandler { + + void publish(String formattedMessage) throws IOException; + void close() throws IOException; + +} diff --git a/task04/src/com/example/task04/RotationFileHandler.java b/task04/src/com/example/task04/RotationFileHandler.java new file mode 100644 index 00000000..570e2f8f --- /dev/null +++ b/task04/src/com/example/task04/RotationFileHandler.java @@ -0,0 +1,55 @@ +package com.example.task04; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +public class RotationFileHandler implements MessageHandler { + + private final String baseFilename; + private final ChronoUnit rotationUnit; + private BufferedWriter writer; + private LocalDateTime lastRotation; + + public RotationFileHandler(String baseFilename, ChronoUnit unit) throws IOException { + if (baseFilename == null || baseFilename.trim().isEmpty()) { + throw new IllegalArgumentException("Base filename cannot be null or empty"); + } + this.baseFilename = baseFilename; + this.rotationUnit = unit; + this.lastRotation = LocalDateTime.now(); + rotate(); + } + + private void rotate() throws IOException { + if (writer != null) { + writer.close(); + } + String timestamp = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss") + .format(lastRotation); + String filename = baseFilename + "-" + timestamp + ".log"; + this.writer = new BufferedWriter(new FileWriter(filename)); + } + + @Override + public void publish(String formattedMessage) throws IOException { + LocalDateTime now = LocalDateTime.now(); + if (rotationUnit.between(lastRotation, now) >= 1) { + lastRotation = now; + rotate(); + } + writer.write(formattedMessage); + writer.newLine(); + writer.flush(); + } + + @Override + public void close() throws IOException { + if (writer != null) { + writer.close(); + } + } +} diff --git a/task04/src/com/example/task04/Task04Main.java b/task04/src/com/example/task04/Task04Main.java index 55917a30..cb59b8cb 100644 --- a/task04/src/com/example/task04/Task04Main.java +++ b/task04/src/com/example/task04/Task04Main.java @@ -1,7 +1,73 @@ package com.example.task04; +import java.time.temporal.ChronoUnit; +import java.io.IOException; public class Task04Main { public static void main(String[] args) { + // 1. Получаем логгер + Logger logger = Logger.getLogger("MyApp"); + // 2. Устанавливаем уровень логирования + logger.setLevel(Logger.Level.INFO); + + // 3. Пример с ConsoleHandler (вывод в консоль) + System.out.println("=== ЛОГ В КОНСОЛЬ ==="); + logger.setHandler(new ConsoleHandler()); + logger.info("Это сообщение INFO в консоль"); + logger.debug("Это DEBUG — не появится, т.к. уровень INFO"); + logger.error("Ошибка в консоли!"); + + // 4. Пример с FileHandler (запись в файл) + try { + System.out.println("\n=== ЛОГ В ФАЙЛ (log.txt) ==="); + logger.setHandler(new FileHandler("log.txt")); + logger.info("Запись в файл: приложение стартовало"); + logger.warning("Предупреждение: мало памяти"); + logger.error("Критическая ошибка: %s", "не удалось сохранить данные"); + + // Обязательно закрываем обработчик + ((FileHandler) logger.getHandler()).close(); + + } catch (IOException e) { + System.err.println("Ошибка при записи в файл: " + e.getMessage()); + } + + // 5. Пример с RotationFileHandler (ротация файлов) + try { + System.out.println("\n=== РОТИРУЕМЫЙ ЛОГ (каждую минуту) ==="); + // Ротация каждую минуту (для демонстрации) + logger.setHandler(new RotationFileHandler("rotated-log", ChronoUnit.MINUTES)); + + logger.info("Сообщение 1 — должно создать новый файл"); + // Если запустить несколько раз в течение минуты — попадёт в тот же файл + logger.info("Сообщение 2 — в тот же файл (если <1 мин)"); + + // Закрываем обработчик + ((RotationFileHandler) logger.getHandler()).close(); + + } catch (IOException e) { + System.err.println("Ошибка при ротации файла: " + e.getMessage()); + } + + // 6. Комбинированный пример: несколько обработчиков + System.out.println("\n=== КОМБИНИРОВАННЫЙ ЛОГ (консоль + файл) ==="); + try { + FileHandler fileHandler = new FileHandler("combined.log"); + ConsoleHandler consoleHandler = new ConsoleHandler(); + + // Логируем одновременно в файл и консоль + logger.setHandler(fileHandler); + logger.info("Это пойдёт в файл combined.log"); + + logger.setHandler(consoleHandler); + logger.info("Это появится в консоли"); + + // Закрываем оба обработчика + fileHandler.close(); + consoleHandler.close(); + + } catch (IOException e) { + System.err.println("Ошибка в комбинированном логе: " + e.getMessage()); + } } }