1
2
3
4
5
6 package org.tailormap.api.repository.events;
7
8 import java.lang.invoke.MethodHandles;
9 import java.util.Map;
10 import java.util.Objects;
11 import java.util.Optional;
12 import java.util.UUID;
13 import org.quartz.JobDataMap;
14 import org.quartz.JobKey;
15 import org.quartz.Scheduler;
16 import org.quartz.SchedulerException;
17 import org.quartz.impl.matchers.GroupMatcher;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.data.rest.core.annotation.HandleAfterDelete;
22 import org.springframework.data.rest.core.annotation.HandleBeforeSave;
23 import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
24 import org.springframework.stereotype.Component;
25 import org.tailormap.api.persistence.SearchIndex;
26 import org.tailormap.api.scheduling.IndexTask;
27 import org.tailormap.api.scheduling.TMJobDataMap;
28 import org.tailormap.api.scheduling.Task;
29 import org.tailormap.api.scheduling.TaskManagerService;
30 import org.tailormap.api.scheduling.TaskType;
31
32
33
34
35
36 @Component
37 @RepositoryEventHandler
38 public class SearchIndexEventHandler {
39 private static final Logger logger =
40 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
41
42 private final Scheduler scheduler;
43 private final TaskManagerService taskManagerService;
44
45 public SearchIndexEventHandler(
46 @Autowired Scheduler scheduler, @Autowired TaskManagerService taskManagerService) {
47 this.scheduler = scheduler;
48 this.taskManagerService = taskManagerService;
49 }
50
51
52
53
54
55
56 @HandleAfterDelete
57 public void afterDeleteSearchIndexEventHandler(SearchIndex searchIndex)
58 throws SchedulerException {
59 if (null != searchIndex.getSchedule()) {
60 JobKey jobKey =
61 taskManagerService.getJobKey(TaskType.INDEX, searchIndex.getSchedule().getUuid());
62
63 if (null != jobKey && scheduler.checkExists(jobKey)) {
64 logger.info(
65 "Deleting index task {} associated with search index: {}",
66 searchIndex.getSchedule().getUuid(),
67 searchIndex.getName());
68 boolean succes = scheduler.deleteJob(jobKey);
69 logger.info(
70 "Task {}:{} deletion {}",
71 jobKey.getGroup(),
72 jobKey.getName(),
73 (succes ? "succeeded" : "failed"));
74 }
75 }
76 }
77
78
79
80
81
82
83
84 @HandleBeforeSave
85 public void beforeSaveSearchIndexEventHandler(SearchIndex searchIndex) throws SchedulerException {
86
87
88
89 if (null != searchIndex.getSchedule()) {
90 if (null == searchIndex.getSchedule().getUuid()) {
91 validateNoTaskExistsForIndex(searchIndex);
92
93 logger.info("Creating new task associated with search index: {}", searchIndex.getName());
94 TMJobDataMap jobDataMap =
95 new TMJobDataMap(
96 Map.of(
97 Task.TYPE_KEY,
98 TaskType.INDEX,
99 Task.DESCRIPTION_KEY,
100 searchIndex.getSchedule().getDescription(),
101 IndexTask.INDEX_KEY,
102 searchIndex.getId().toString()));
103 if (null != searchIndex.getSchedule().getPriority()
104 && searchIndex.getSchedule().getPriority() > 0) {
105 jobDataMap.put(Task.PRIORITY_KEY, searchIndex.getSchedule().getPriority());
106 }
107 final UUID uuid =
108 taskManagerService.createTask(
109 IndexTask.class, jobDataMap, searchIndex.getSchedule().getCronExpression());
110 searchIndex.getSchedule().setUuid(uuid);
111 } else {
112
113 logger.info(
114 "Updating task {} associated with search index: {}",
115 searchIndex.getSchedule().getUuid(),
116 searchIndex.getName());
117
118 JobKey jobKey =
119 taskManagerService.getJobKey(TaskType.INDEX, searchIndex.getSchedule().getUuid());
120 if (null != jobKey && scheduler.checkExists(jobKey)) {
121
122 JobDataMap jobDataMap = scheduler.getJobDetail(jobKey).getJobDataMap();
123 jobDataMap.put(Task.DESCRIPTION_KEY, searchIndex.getSchedule().getDescription());
124 jobDataMap.put(Task.CRON_EXPRESSION_KEY, searchIndex.getSchedule().getCronExpression());
125 if (null != searchIndex.getSchedule().getPriority()
126 && searchIndex.getSchedule().getPriority() > 0) {
127 jobDataMap.put(Task.PRIORITY_KEY, searchIndex.getSchedule().getPriority());
128 }
129
130 taskManagerService.updateTask(jobKey, new TMJobDataMap(jobDataMap));
131 }
132 }
133 }
134 }
135
136
137
138
139
140
141
142 private void validateNoTaskExistsForIndex(SearchIndex searchIndex) throws SchedulerException {
143 Optional<JobDataMap> jobDataMapOptional =
144 scheduler.getJobKeys(GroupMatcher.groupEquals(TaskType.INDEX.getValue())).stream()
145 .map(
146 jobKey -> {
147 try {
148 return scheduler.getJobDetail(jobKey).getJobDataMap();
149 } catch (SchedulerException e) {
150 logger.error("Error getting task detail", e);
151 return null;
152 }
153 })
154 .filter(Objects::nonNull)
155 .filter(
156 jobDataMap ->
157 searchIndex.getId().equals(jobDataMap.getLongValue(IndexTask.INDEX_KEY)))
158 .findFirst();
159
160 if (jobDataMapOptional.isPresent()) {
161 logger.warn("A scheduled task already exists for search index: {}", searchIndex.getName());
162 throw new SchedulerException(
163 "A scheduled task already exists for search index: '%s'"
164 .formatted(searchIndex.getName()));
165 }
166 }
167 }