1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.common.events;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Hashtable;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.stream.Collectors;
27
28 import org.apache.logging.log4j.LogManager;
29 import org.apache.logging.log4j.Logger;
30 import org.mycore.common.MCRException;
31 import org.mycore.common.config.MCRConfiguration2;
32 import org.mycore.common.config.MCRConfigurationException;
33
34
35
36
37
38
39
40
41
42
43
44 public class MCREventManager {
45
46 public static final String CONFIG_PREFIX = "MCR.EventHandler.";
47
48
49 public static final boolean FORWARD = true;
50
51
52 public static final boolean BACKWARD = false;
53
54 private static Logger logger = LogManager.getLogger(MCREventManager.class);
55
56 private static MCREventManager instance;
57
58
59 private Hashtable<MCREvent.ObjectType, List<MCREventHandler>> handlers;
60
61 private MCREventManager() {
62 handlers = new Hashtable<>();
63
64 Map<String, String> props = MCRConfiguration2.getPropertiesMap()
65 .entrySet()
66 .stream()
67 .filter(p -> p.getKey().startsWith(CONFIG_PREFIX))
68 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
69
70 List<String> propertyKeyList = new ArrayList<>(props.size());
71 for (Object name : props.keySet()) {
72 String key = name.toString();
73 if (!key.startsWith(CONFIG_PREFIX + "Mode.")) {
74 propertyKeyList.add(key);
75 }
76 }
77 Collections.sort(propertyKeyList);
78
79 for (String propertyKey : propertyKeyList) {
80 EventHandlerProperty eventHandlerProperty = new EventHandlerProperty(propertyKey);
81
82 MCREvent.ObjectType type = eventHandlerProperty.getType();
83 String mode = eventHandlerProperty.getMode();
84
85 logger.debug("EventManager instantiating handler {} for type {}", props.get(propertyKey), type);
86
87 if (propKeyIsSet(propertyKey)) {
88 addEventHandler(type, getEventHandler(mode, propertyKey));
89 }
90 }
91 }
92
93
94
95
96
97
98 public static synchronized MCREventManager instance() {
99 if (instance == null) {
100 instance = new MCREventManager();
101 }
102
103 return instance;
104 }
105
106 private boolean propKeyIsSet(String propertyKey) {
107 return MCRConfiguration2.getString(propertyKey).isPresent();
108 }
109
110 private List<MCREventHandler> getOrCreateEventHandlerListOfType(MCREvent.ObjectType type) {
111 return handlers.computeIfAbsent(type, k -> new ArrayList<>());
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 public void handleEvent(MCREvent evt, boolean direction) {
131 List<MCREventHandler> list = handlers.get(evt.getObjectType());
132 if (list == null) {
133 return;
134 }
135
136 int first = direction ? 0 : list.size() - 1;
137 int last = direction ? list.size() - 1 : 0;
138 int step = direction ? 1 : -1;
139 int undoPos = first;
140
141 Exception handleEventExceptionCaught = null;
142 for (int i = first; i != last + step; i += step) {
143 MCREventHandler eh = list.get(i);
144 logger.debug("EventManager {} {} calling handler {}", evt.getObjectType(), evt.getEventType(),
145 eh.getClass().getName());
146
147 try {
148 eh.doHandleEvent(evt);
149 } catch (Exception ex) {
150 handleEventExceptionCaught = ex;
151 logger.error("Exception caught while calling event handler", ex);
152 logger.error("Trying rollback by calling undo method of event handlers");
153
154 undoPos = i;
155
156 break;
157 }
158 }
159
160
161 for (int i = undoPos - step; i != first - step; i -= step) {
162 MCREventHandler eh = list.get(i);
163 logger.debug("EventManager {} {} calling undo of handler {}", evt.getObjectType(), evt.getEventType(),
164 eh.getClass().getName());
165
166 try {
167 eh.undoHandleEvent(evt);
168 } catch (Exception ex) {
169 logger.error("Exception caught while calling undo of event handler", ex);
170 }
171 }
172
173 if (handleEventExceptionCaught != null) {
174 String msg = "Exception caught in EventHandler, rollback by calling undo of successfull handlers done.";
175 throw new MCRException(msg, handleEventExceptionCaught);
176 }
177 }
178
179
180 public void handleEvent(MCREvent evt) throws MCRException {
181 handleEvent(evt, MCREventManager.FORWARD);
182 }
183
184
185
186
187
188
189 public MCREventManager addEventHandler(MCREvent.ObjectType type, MCREventHandler handler) {
190 getOrCreateEventHandlerListOfType(type).add(handler);
191 return this;
192 }
193
194
195
196
197
198
199
200 public MCREventManager addEventHandler(MCREvent.ObjectType type, MCREventHandler handler, int index) {
201 getOrCreateEventHandlerListOfType(type).add(index, handler);
202 return this;
203 }
204
205
206
207
208
209
210
211 public MCREventManager removeEventHandler(MCREvent.ObjectType type, MCREventHandler handler) {
212 List<MCREventHandler> handlerList = this.handlers.get(type);
213 handlerList.remove(handler);
214 if (handlerList.isEmpty()) {
215 this.handlers.remove(type);
216 }
217 return this;
218 }
219
220
221
222
223
224
225 public MCREventManager removeEventHandler(MCREvent.ObjectType type) {
226 this.handlers.remove(type);
227 return this;
228 }
229
230
231
232
233 public MCREventManager clear() {
234 this.handlers.clear();
235 return this;
236 }
237
238 public MCREventHandler getEventHandler(String mode, String propertyValue) {
239 if ("Class".equals(mode)) {
240 return MCRConfiguration2.<MCREventHandler>getSingleInstanceOf(propertyValue)
241 .orElseThrow(() -> MCRConfiguration2.createConfigurationException(propertyValue));
242 }
243 String className = CONFIG_PREFIX + "Mode." + mode;
244 MCREventHandlerInitializer configuredInitializer = MCRConfiguration2
245 .<MCREventHandlerInitializer>getSingleInstanceOf(className)
246 .orElseThrow(() -> MCRConfiguration2.createConfigurationException(className));
247 return configuredInitializer.getInstance(propertyValue);
248 }
249
250 public interface MCREventHandlerInitializer {
251 MCREventHandler getInstance(String propertyValue);
252 }
253
254
255
256
257
258
259
260
261
262 private class EventHandlerProperty {
263
264 private MCREvent.ObjectType type;
265
266 private String mode;
267
268 EventHandlerProperty(String propertyKey) {
269 String[] splitedKey = propertyKey.split("\\.");
270 if (splitedKey.length != 5) {
271 throw new MCRConfigurationException("Property key " + propertyKey + " for event handler not valid.");
272 }
273
274 this.setType(MCREvent.ObjectType.fromClassName(splitedKey[2]));
275 this.setMode(splitedKey[4]);
276 }
277
278 public MCREvent.ObjectType getType() {
279 return type;
280 }
281
282 private void setType(MCREvent.ObjectType type) {
283 this.type = type;
284 }
285
286 public String getMode() {
287 return mode;
288 }
289
290 private void setMode(String mode) {
291 this.mode = mode;
292 }
293
294 }
295 }