├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── MyObject.txt ├── TaskTracker.iml ├── src ├── Main.java ├── subscribers │ ├── BrowserLauncher.java │ ├── FileLogger.java │ ├── PopupNotifier.java │ └── PopupNotifierWindow.java └── tracker │ ├── api │ ├── IJournal.java │ ├── IJournalSubscriber.java │ ├── IManager.java │ ├── ITask.java │ ├── Period.java │ └── PeriodOverlapException.java │ └── impl │ ├── Journal.java │ ├── Manager.java │ └── Task.java └── temp /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1.8 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MyObject.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sunagatov/TaskTracker/5f652f1b8a34cf24c9781dcf511b745427839f8e/MyObject.txt -------------------------------------------------------------------------------- /TaskTracker.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Main.java: -------------------------------------------------------------------------------- 1 | import subscribers.PopupNotifier; 2 | import tracker.api.*; 3 | import tracker.impl.Manager; 4 | 5 | import java.io.IOException; 6 | import java.time.LocalDateTime; 7 | import java.time.format.DateTimeFormatter; 8 | import java.util.Scanner; 9 | import java.util.stream.Stream; 10 | 11 | public class Main { 12 | //20.12.2016 13:40:20 13 | public static void main(String[] args) { 14 | System.out.println("Welcome to the TaskTracker by Zufar! "); 15 | Scanner sc = new Scanner(System.in); 16 | IJournal journal = null; 17 | StringBuilder message1 = new StringBuilder("\nWhat do you want with journal? \n"); 18 | message1.append(" - create \n"); 19 | message1.append(" - load \n"); 20 | String command; 21 | while (true) { 22 | System.out.print(message1); 23 | command = sc.nextLine(); 24 | switch (command) { 25 | case "create": { 26 | journal = Manager.getInstance().createJournal(); 27 | System.out.println("\nJournal created successfully."); 28 | break; 29 | } 30 | case "load": { 31 | try { 32 | journal = Manager.getInstance().loadJournal("C:\\Users\\ьр\\IdeaProjects\\TaskTracker"); 33 | } catch (IOException | ClassNotFoundException e) { 34 | System.out.println("\nError! Journal can not be loaded."); 35 | continue; 36 | } 37 | break; 38 | } 39 | default: { 40 | System.out.println("\nThe wrong command! Try again..."); 41 | continue; 42 | } 43 | } 44 | break; 45 | } 46 | journal.register(new PopupNotifier()); 47 | StringBuilder message = new StringBuilder("\nWhat do you want with tasks? \n"); 48 | message.append(" - add \n"); 49 | message.append(" - delete \n"); 50 | message.append(" - show \n"); 51 | message.append(" - exit \n"); 52 | message.append("Enter a command: "); 53 | while (true) { 54 | System.out.print(message); 55 | command = sc.nextLine(); 56 | switch (command) { 57 | case "add": { 58 | System.out.print("\nEnter task name: "); 59 | String name = sc.nextLine(); 60 | System.out.print("\nEnter task description: "); 61 | String description = sc.nextLine(); 62 | while (true) { 63 | try { 64 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"); 65 | System.out.print("\nEnter start time. Format is DD.MM.YYYY HH:MM:SS: "); 66 | LocalDateTime startTime = LocalDateTime.parse(sc.nextLine(), formatter); 67 | if (LocalDateTime.now().isAfter(startTime)) { 68 | System.out.print("Error! StartTime must be after current time."); 69 | continue; 70 | } 71 | System.out.print("\nEnter End time. Format is DD.MM.YYYY HH:MM:SS: "); 72 | LocalDateTime endTime = LocalDateTime.parse(sc.nextLine(), formatter); 73 | if (endTime.isBefore(startTime)) { 74 | System.out.println("Error! EndTime must be after StarTime."); 75 | continue; 76 | } 77 | ITask task = journal.createTask(new Period(startTime, endTime)); 78 | task.setDescription(description); 79 | task.setName(name); 80 | break; 81 | } catch (Exception e) { 82 | System.out.println("Error! Please type the time in the right way...\n"); 83 | } 84 | } 85 | 86 | break; 87 | } 88 | 89 | case "delete": { 90 | System.out.print("Write a task name: "); 91 | String taskName = sc.nextLine().toLowerCase(); 92 | Stream s = journal.getTasks(new Period(LocalDateTime.MIN, LocalDateTime.MAX)).stream(). 93 | filter((task) -> task.getName().toLowerCase().contains(taskName)); 94 | if (s.count() == 0 || journal.getNumberOfTasks() == 0) { 95 | System.out.println("Error! The task with that name is not existed!"); 96 | continue; 97 | } 98 | journal.getTasks(new Period(LocalDateTime.MIN, LocalDateTime.MAX)).stream(). 99 | filter((task) -> task.getName().toLowerCase().contains(taskName)). 100 | forEach(journal::removeTask); 101 | System.out.println("\nThe Task was removed successfully."); 102 | break; 103 | } 104 | 105 | case "show": { 106 | System.out.println("Number of Tasks: " + journal.getNumberOfTasks()); 107 | System.out.println("================"); 108 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"); 109 | final IJournal finalJournal = journal; 110 | journal.getTasks(new Period(LocalDateTime.MIN, LocalDateTime.MAX)).stream(). 111 | forEach((task) -> { 112 | Period period = finalJournal.getTaskPeriod(task); 113 | System.out.println("ID: " + task.getId()); 114 | System.out.println("Name: " + task.getName()); 115 | System.out.println("Description: " + task.getDescription()); 116 | System.out.println("StartTime: " + period.getStart().format(formatter)); 117 | System.out.println("EndTime: " + period.getEnd().format(formatter)); 118 | System.out.println("================"); 119 | }); 120 | break; 121 | } 122 | 123 | case "exit": { 124 | /* try { 125 | Manager.getInstance().saveJournal(journal, "MyObject.txt"); 126 | } catch (IOException e) { 127 | e.printStackTrace(); 128 | }*/ 129 | //System.out.println("\nJournal was saved successfully."); 130 | return; 131 | } 132 | 133 | default: 134 | System.out.println("\nThe wrong command! Try again..."); 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/subscribers/BrowserLauncher.java: -------------------------------------------------------------------------------- 1 | package subscribers; 2 | 3 | import tracker.api.IJournal; 4 | import tracker.api.IJournalSubscriber; 5 | import tracker.api.ITask; 6 | 7 | public class BrowserLauncher implements IJournalSubscriber { 8 | @Override 9 | public void onEvent(IJournal sender, ITask task) { 10 | // https://tasktracker.org/?journal={$id}&task={$id} 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/subscribers/FileLogger.java: -------------------------------------------------------------------------------- 1 | package subscribers; 2 | 3 | import tracker.api.IJournal; 4 | import tracker.api.IJournalSubscriber; 5 | import tracker.api.ITask; 6 | 7 | public class FileLogger implements IJournalSubscriber { 8 | @Override 9 | public void onEvent(IJournal sender, ITask task) { 10 | System.out.println(String.format("journal=%d, taskId=%d, taskName=%s, taskDesc=%s", 11 | sender.getId(), task.getId(), task.getName(), task.getDescription())); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/subscribers/PopupNotifier.java: -------------------------------------------------------------------------------- 1 | package subscribers; 2 | 3 | import tracker.api.IJournal; 4 | import tracker.api.IJournalSubscriber; 5 | import tracker.api.ITask; 6 | 7 | import java.io.Serializable; 8 | 9 | public class PopupNotifier implements IJournalSubscriber { 10 | @Override 11 | public void onEvent(IJournal sender, ITask task) { 12 | PopupNotifierWindow w = new PopupNotifierWindow(sender, task); 13 | w.setVisible(true); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/subscribers/PopupNotifierWindow.java: -------------------------------------------------------------------------------- 1 | package subscribers; 2 | 3 | import tracker.api.IJournal; 4 | import tracker.api.ITask; 5 | import tracker.api.Period; 6 | import tracker.api.PeriodOverlapException; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | import java.time.LocalDateTime; 11 | import java.time.temporal.ChronoUnit; 12 | 13 | class PopupNotifierWindow extends JFrame { 14 | 15 | PopupNotifierWindow(IJournal journal, ITask task) { 16 | setSize(400, 200); 17 | Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 18 | setLocation(dim.width / 2 - getSize().width / 2, dim.height / 2 - getSize().height / 2); 19 | setLayout(new FlowLayout()); 20 | setTitle(task.getName()); 21 | JLabel nameLabel = new JLabel(); 22 | nameLabel.setText(task.getDescription()); 23 | JButton closeButton = new JButton(); 24 | closeButton.setText("Close"); 25 | closeButton.addActionListener((actionEvent) -> dispose()); 26 | JButton postponeButton = new JButton(); 27 | postponeButton.setText("Postpone"); 28 | postponeButton.addActionListener((actionEvent) -> { 29 | // Запросить новый период 30 | LocalDateTime start = LocalDateTime.now().plusSeconds(5); 31 | Period old = journal.getTaskPeriod(task); 32 | long seconds = ChronoUnit.SECONDS.between(old.getStart(), old.getEnd()); 33 | LocalDateTime end = start.plusSeconds(seconds); 34 | try { 35 | journal.setTaskPeriod(task, new Period(start, end)); 36 | } catch (PeriodOverlapException e) { 37 | // Неверный период, запросить снова 38 | } 39 | dispose(); 40 | }); 41 | add(nameLabel); 42 | add(closeButton); 43 | add(postponeButton); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/tracker/api/IJournal.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * Базовый интерфейс для всех журналов. 7 | */ 8 | public interface IJournal { 9 | /** 10 | * Возвращает уникальный идентификатор журнала. 11 | * 12 | * @return Уникальный идентификатор журнала. 13 | */ 14 | int getId(); 15 | 16 | /** 17 | * Возвращает количество задач. 18 | * 19 | * @return Количество задач. 20 | */ 21 | int getNumberOfTasks(); 22 | 23 | /** 24 | * Возвращает коллекцию задач из указанного периода. 25 | * 26 | * @param period Период для поиска задач. 27 | * @return Коллекция задач из указанного периода. 28 | */ 29 | Collection getTasks(Period period); 30 | 31 | /** 32 | * Создаёт новую задачу с указанным периодом в коллекции задач. 33 | * 34 | * @param period Период задачи. 35 | * @return Созданная задача. 36 | * @throws PeriodOverlapException Если период новой задачи пересекается с любым из периодов уже существующих задач. 37 | */ 38 | ITask createTask(Period period) throws PeriodOverlapException; 39 | 40 | /** 41 | * Удаляет задачу из коллекции. 42 | * 43 | * @param task Удаляемая задача. 44 | */ 45 | void removeTask(ITask task); 46 | 47 | /** 48 | * Возвращает период указанной задачи. 49 | * 50 | * @param task Задача, период которой нужно получить. 51 | * @return Период указанной задачи. 52 | */ 53 | Period getTaskPeriod(ITask task); 54 | 55 | /** 56 | * Устанавливает новый период для задачи. 57 | * 58 | * @param task Задача, период которой нужно установить. 59 | * @param period Новое значение периода. 60 | * @throws PeriodOverlapException Если новый период задачи пересекается с любым из периодов других задач. 61 | */ 62 | void setTaskPeriod(ITask task, Period period) throws PeriodOverlapException; 63 | 64 | /** 65 | * Регистрирует нового подписчика на событие наступления задачи. 66 | * 67 | * @param subscriber Новый подписчик. 68 | */ 69 | void register(IJournalSubscriber subscriber); 70 | 71 | /** 72 | * Удаляет подписчика из события наступления задачи. 73 | * 74 | * @param subscriber Удаляемый подписчик. 75 | */ 76 | void unregister(IJournalSubscriber subscriber); 77 | } 78 | -------------------------------------------------------------------------------- /src/tracker/api/IJournalSubscriber.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | /** 4 | * Базовый интерфейс для всех подписчиков на событие наступления задачи в журнале. 5 | */ 6 | public interface IJournalSubscriber { 7 | /** 8 | * Обрабатывает событие наступления задачи. 9 | * 10 | * @param sender Журнал, в котором произошло событие. 11 | * @param task Задача, время наступления которой подошло. 12 | */ 13 | void onEvent(IJournal sender, ITask task); 14 | } 15 | -------------------------------------------------------------------------------- /src/tracker/api/IManager.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Базовый интерфейс для управления журналами. 7 | */ 8 | public interface IManager { 9 | /** 10 | * Загружает журнал по его имени. 11 | * 12 | * @param path Имя журнала. 13 | * @return Загруженный журнал. 14 | * @throws IOException Если возникла ошибка при загрузке журнала с указанным именем. 15 | */ 16 | IJournal loadJournal(String path) throws IOException, ClassNotFoundException; 17 | 18 | /** 19 | * Сохраняет журнал, используя указанное имя. 20 | * 21 | * @param journal Сохраняемый журнал. 22 | * @param path Имя сохраняемого журнала. 23 | * @throws IOException Если возникла ошибка при сохранении журнала с указанным именем. 24 | */ 25 | void saveJournal(IJournal journal, String path) throws IOException; 26 | 27 | 28 | /** 29 | * Создает новый журнал. 30 | * 31 | * @return Новый журнал. 32 | */ 33 | IJournal createJournal(); 34 | } 35 | -------------------------------------------------------------------------------- /src/tracker/api/ITask.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | /** 4 | * Базовый интерфейс задачи. 5 | */ 6 | public interface ITask { 7 | /** 8 | * Возвращает идентификатор задачи (уникальный в пределах журнала). 9 | * 10 | * @return Идентификатор задачи (уникальный в пределах журнала). 11 | */ 12 | int getId(); 13 | 14 | /** 15 | * Возвращает название задачи. 16 | * 17 | * @return Название задачи. 18 | */ 19 | String getName(); 20 | 21 | /** 22 | * Возвращает описание задачи. 23 | * 24 | * @return Описание задачи. 25 | */ 26 | String getDescription(); 27 | 28 | /** 29 | * Устанавливает новое название задачи. 30 | * 31 | * @param name Новое название. 32 | */ 33 | void setName(String name); 34 | 35 | /** 36 | * Устанавливает новое описание задачи. 37 | * 38 | * @param description Новое описание. 39 | */ 40 | void setDescription(String description); 41 | } 42 | -------------------------------------------------------------------------------- /src/tracker/api/Period.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | import java.io.Serializable; 4 | import java.time.LocalDateTime; 5 | 6 | /** 7 | * Описывает период времени. 8 | */ 9 | public class Period { 10 | private final LocalDateTime start; 11 | private final LocalDateTime end; 12 | 13 | /** 14 | * Создаёт объект, описывающий фиксированный период времени. 15 | * @param start Начало периода. 16 | * @param end Конец периода. 17 | * @throws IllegalArgumentException Если конец периода предшествует началу. 18 | */ 19 | public Period(LocalDateTime start, LocalDateTime end) { 20 | if (start.isAfter(end)) 21 | throw new IllegalArgumentException(); 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | /** 27 | * Возвращает начало периода. 28 | * @return Начало периода. 29 | */ 30 | public LocalDateTime getStart() { 31 | return start; 32 | } 33 | 34 | /** 35 | * Возвращает конец периода. 36 | * @return Конец периода. 37 | */ 38 | public LocalDateTime getEnd() { 39 | return end; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/tracker/api/PeriodOverlapException.java: -------------------------------------------------------------------------------- 1 | package tracker.api; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * Исключение, генерируемое в случае наличия задач с пересекающимися периодами. 7 | */ 8 | public class PeriodOverlapException extends Exception { 9 | private Collection overlappedTasks; 10 | 11 | /** 12 | * Создаёт исключение со списком задач, периоды которых пересекаются с новым периодом. 13 | * 14 | * @param overlappedTasks Список задач, периоды которых пересекаются с новым периодом. 15 | */ 16 | public PeriodOverlapException(Collection overlappedTasks) { 17 | this.overlappedTasks = overlappedTasks; 18 | } 19 | 20 | /** 21 | * Возвращает список задач, периоды которых пересекаются с новым периодом. 22 | * 23 | * @return Список задач, периоды которых пересекаются с новым периодом. 24 | */ 25 | public Collection getOverlappedTasks() { 26 | return overlappedTasks; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/tracker/impl/Journal.java: -------------------------------------------------------------------------------- 1 | package tracker.impl; 2 | 3 | import tracker.api.*; 4 | import tracker.api.Period; 5 | 6 | import java.io.Serializable; 7 | import java.time.*; 8 | import java.util.*; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * Реализация интерфейса {@link IJournal}. 13 | */ 14 | class Journal implements IJournal { 15 | private class TimerTask extends java.util.TimerTask { 16 | private ITask task; 17 | 18 | public TimerTask(ITask task) { 19 | this.task = task; 20 | } 21 | 22 | public ITask getTask() { 23 | return task; 24 | } 25 | 26 | @Override 27 | public void run() { 28 | synchronized (subscribers) { 29 | for (IJournalSubscriber subscriber : subscribers) { 30 | new Thread(() -> subscriber.onEvent(Journal.this, task)).run(); 31 | } 32 | } 33 | Journal.this.reschedule(); 34 | } 35 | } 36 | 37 | private final int id; 38 | private Map data = new HashMap<>(); 39 | 40 | private List subscribers = new ArrayList<>(); 41 | 42 | private Timer timer = new Timer(); 43 | private TimerTask timerTask; 44 | 45 | /** 46 | * Создаёт журнал с указанным идентификатором. 47 | * 48 | * @param id Идентификатор журнала. 49 | */ 50 | public Journal(int id) { 51 | this.id = id; 52 | } 53 | 54 | @Override 55 | public int getId() { 56 | return id; 57 | } 58 | 59 | @Override 60 | public int getNumberOfTasks() { 61 | return data.size(); 62 | } 63 | 64 | @Override 65 | public synchronized Collection getTasks(Period period) { 66 | LocalDateTime start = period.getStart(); 67 | LocalDateTime end = period.getEnd(); 68 | return data.entrySet().stream(). 69 | filter((entry) -> { 70 | LocalDateTime taskStart = entry.getValue().getStart(); 71 | LocalDateTime taskEnd = entry.getValue().getEnd(); 72 | return start.isBefore(taskStart) && taskStart.isBefore(end) || 73 | start.isBefore(taskEnd) && taskEnd.isBefore(end); 74 | }). 75 | map((entry) -> entry.getKey()). 76 | collect(Collectors.toList()); 77 | } 78 | 79 | @Override 80 | public synchronized ITask createTask(Period period) throws PeriodOverlapException { 81 | checkPeriod(null, period); 82 | ITask task = new Task(generateTaskId()); 83 | data.put(task, period); 84 | rescheduleOnAdd(task); 85 | return task; 86 | } 87 | 88 | @Override 89 | public synchronized void removeTask(ITask task) { 90 | data.remove(task); 91 | rescheduleOnRemove(task); 92 | } 93 | 94 | @Override 95 | public synchronized Period getTaskPeriod(ITask task) { 96 | return data.get(task); 97 | } 98 | 99 | @Override 100 | public synchronized void setTaskPeriod(ITask task, Period period) throws PeriodOverlapException { 101 | checkPeriod(task, period); 102 | Period oldPeriod = data.get(task); 103 | data.put(task, period); 104 | rescheduleOnUpdate(task, oldPeriod); 105 | } 106 | 107 | @Override 108 | public synchronized void register(IJournalSubscriber subscriber) { 109 | subscribers.add(subscriber); 110 | } 111 | 112 | @Override 113 | public synchronized void unregister(IJournalSubscriber subscriber) { 114 | subscribers.remove(subscriber); 115 | } 116 | 117 | private void checkPeriod(ITask task, Period newPeriod) throws PeriodOverlapException { 118 | LocalDateTime newStart = newPeriod.getStart(); 119 | LocalDateTime newEnd = newPeriod.getEnd(); 120 | List overlaps = data.entrySet().stream(). 121 | filter((entry) -> { 122 | if (entry.getKey() == task) 123 | return false; 124 | Period period = entry.getValue(); 125 | LocalDateTime start = period.getStart(); 126 | LocalDateTime end = period.getEnd(); 127 | return start.isBefore(newStart) && newStart.isBefore(end) || 128 | start.isBefore(newEnd) && newEnd.isBefore(end) || 129 | newStart.isBefore(start) && end.isBefore(newEnd) || start.isEqual(newStart)||end.isEqual(newEnd); 130 | }). 131 | map((entry) -> entry.getKey()). 132 | collect(Collectors.toList()); 133 | if (overlaps.size() > 0) 134 | throw new PeriodOverlapException(overlaps); 135 | } 136 | 137 | private int generateTaskId() { 138 | while (data.entrySet().stream().anyMatch((entry) -> entry.getKey().getId() == taskId)) 139 | ++taskId; 140 | return taskId; 141 | } 142 | 143 | private int taskId = 0; 144 | 145 | private void rescheduleOnAdd(ITask addedTask) { 146 | // Оптимизировать (вызывать reschedule только при действительной необходимости 147 | reschedule(); 148 | } 149 | 150 | private void rescheduleOnRemove(ITask removedTask) { 151 | // Оптимизировать (вызывать reschedule только при действительной необходимости 152 | reschedule(); 153 | } 154 | 155 | private void rescheduleOnUpdate(ITask updatedTask, Period oldPeriod) { 156 | // Оптимизировать (вызывать reschedule только при действительной необходимости 157 | reschedule(); 158 | } 159 | 160 | private synchronized void reschedule() { 161 | LocalDateTime now = LocalDateTime.now(); 162 | if (timerTask != null) { 163 | timerTask.cancel(); 164 | timer.purge(); 165 | timerTask = null; 166 | } 167 | Optional> nextEntry = data.entrySet().stream(). 168 | filter((entry) -> entry.getValue().getStart().isAfter(now)). 169 | min(Comparator.comparing((entry) -> entry.getValue().getStart())); 170 | 171 | 172 | nextEntry.ifPresent((entry) -> 173 | { 174 | long millis = java.time.Duration.between(LocalDateTime.now(), entry.getValue().getStart()).toMillis(); 175 | if (millis < 0) 176 | millis = 0; 177 | timerTask = new TimerTask(entry.getKey()); 178 | timer.schedule(timerTask, millis); 179 | }); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/tracker/impl/Manager.java: -------------------------------------------------------------------------------- 1 | package tracker.impl; 2 | 3 | import tracker.api.IJournal; 4 | import tracker.api.IManager; 5 | 6 | import java.io.*; 7 | import java.util.Random; 8 | 9 | /** 10 | * Реализация интерфейса {@link IManager}. 11 | * Шаблон проектирования "Одиночка". 12 | */ 13 | public class Manager implements IManager { 14 | private static IManager intance = new Manager(); 15 | 16 | /** 17 | * Возвращает единственный экземпляр {@link IManager}, осуществляющий управление журналами. 18 | * 19 | * @return Единственный экземпляр {@link IManager}, осуществляющий управление журналами. 20 | */ 21 | public static IManager getInstance() { 22 | return intance; 23 | } 24 | 25 | private Manager() { 26 | } 27 | 28 | @Override 29 | public IJournal loadJournal(String path) throws IOException, ClassNotFoundException { 30 | ObjectInputStream oin; 31 | try (FileInputStream fis = new FileInputStream(path)) { 32 | oin = new ObjectInputStream(fis); 33 | return (IJournal) oin.readObject(); 34 | } 35 | } 36 | 37 | @Override 38 | public void saveJournal(IJournal journal, String path) throws IOException { 39 | try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("MyObject.txt"))) { 40 | out.writeObject(journal); 41 | out.close(); 42 | } 43 | //throw new UnsupportedOperationException(); 44 | } 45 | 46 | @Override 47 | public IJournal createJournal() { 48 | Random r = new Random(); 49 | return new Journal(getRandomNumberInRange(0, Integer.MAX_VALUE-1)); 50 | } 51 | 52 | private static int getRandomNumberInRange(int min, int max) { 53 | if (min >= max) { 54 | throw new IllegalArgumentException("max must be greater than min"); 55 | } 56 | Random r = new Random(); 57 | return r.nextInt((max - min) + 1) + min; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/tracker/impl/Task.java: -------------------------------------------------------------------------------- 1 | package tracker.impl; 2 | 3 | import tracker.api.ITask; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Реализация интерфейса {@link ITask}. 9 | */ 10 | class Task implements ITask { 11 | private final int id; 12 | private String name; 13 | private String description; 14 | 15 | /** 16 | * Создаёт задачу с указанным идентификатором. 17 | * 18 | * @param id Идентификатор задачи. 19 | */ 20 | public Task(int id) { 21 | this.id = id; 22 | } 23 | 24 | @Override 25 | public int getId() { 26 | return id; 27 | } 28 | 29 | @Override 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | @Override 35 | public String getDescription() { 36 | return description; 37 | } 38 | 39 | @Override 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | @Override 45 | public void setDescription(String description) { 46 | this.description = description; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /temp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sunagatov/TaskTracker/5f652f1b8a34cf24c9781dcf511b745427839f8e/temp --------------------------------------------------------------------------------