Skip to content

Method: setParent(EntityLifecycleListenerManager)

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model.metamodel;
16:
17: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
18: import cz.cvut.kbss.jopa.model.annotations.EntityListeners;
19: import cz.cvut.kbss.jopa.model.lifecycle.LifecycleEvent;
20:
21: import java.lang.reflect.InvocationTargetException;
22: import java.lang.reflect.Method;
23: import java.util.*;
24:
25: /**
26: * Manages entity lifecycle callbacks declared either in the entity (entity lifecycle callbacks) or in its entity
27: * listener (entity listener callbacks) and provides means for their invocation.
28: */
29: public class EntityLifecycleListenerManager {
30:
31: private static final EntityLifecycleListenerManager EMPTY = new EntityLifecycleListenerManager();
32:
33: private EntityLifecycleListenerManager parent;
34:
35: private final Map<LifecycleEvent, Method> lifecycleCallbacks = new EnumMap<>(LifecycleEvent.class);
36:
37: private List<Object> entityListeners;
38:
39: private Map<Object, Map<LifecycleEvent, Method>> entityListenerCallbacks;
40:
41: /**
42: * Gets default instance of this manager, which contains no listeners and does nothing on invocation.
43: *
44: * @return Default {@link EntityLifecycleListenerManager} instance
45: */
46: public static EntityLifecycleListenerManager empty() {
47: return EMPTY;
48: }
49:
50: /**
51: * Calls pre-persist callbacks for the specified instance.
52: * <p>
53: * These include:
54: * <ul>
55: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
56: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
57: * </ul>
58: *
59: * @param instance The instance for persist
60: */
61: public void invokePrePersistCallbacks(Object instance) {
62: invokeCallbacks(instance, LifecycleEvent.PRE_PERSIST);
63: }
64:
65: private void invokeCallbacks(Object instance, LifecycleEvent lifecycleEvent) {
66: invokeEntityListenerCallbacks(instance, lifecycleEvent);
67: invokeInternalCallbacks(instance, lifecycleEvent);
68: }
69:
70: private void invokeEntityListenerCallbacks(Object instance, LifecycleEvent lifecycleEvent) {
71: if (parent != null) {
72: parent.invokeEntityListenerCallbacks(instance, lifecycleEvent);
73: }
74: if (entityListeners != null) {
75: entityListeners.forEach(listener -> {
76: getEntityListenerCallback(listener, lifecycleEvent).ifPresent(method -> {
77: if (!method.isAccessible()) {
78: method.setAccessible(true);
79: }
80: try {
81: method.invoke(listener, instance);
82: } catch (IllegalAccessException | InvocationTargetException e) {
83: throw new OWLPersistenceException("Unable to invoke entity listener method " + method, e);
84: }
85: });
86: });
87: }
88: }
89:
90: private Optional<Method> getEntityListenerCallback(Object listener, LifecycleEvent lifecycleEvent) {
91: final Map<LifecycleEvent, Method> callbacks = entityListenerCallbacks.get(listener);
92: return Optional.ofNullable(callbacks.get(lifecycleEvent));
93: }
94:
95: private void invokeInternalCallbacks(Object instance, LifecycleEvent lifecycleEvent) {
96: if (parent != null) {
97: parent.invokeInternalCallbacks(instance, lifecycleEvent);
98: }
99: if (lifecycleCallbacks.containsKey(lifecycleEvent)) {
100: final Method listener = lifecycleCallbacks.get(lifecycleEvent);
101: if (!listener.isAccessible()) {
102: listener.setAccessible(true);
103: }
104: try {
105: listener.invoke(instance);
106: } catch (IllegalAccessException | InvocationTargetException e) {
107: throw new OWLPersistenceException("Unable to invoke method lifecycle listener " + listener, e);
108: }
109: }
110: }
111:
112: /**
113: * Calls post-persist callbacks for the specified instance.
114: * <p>
115: * These include:
116: * <ul>
117: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
118: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
119: * </ul>
120: *
121: * @param instance The newly persisted instance
122: */
123: public void invokePostPersistCallbacks(Object instance) {
124: invokeCallbacks(instance, LifecycleEvent.POST_PERSIST);
125: }
126:
127: /**
128: * Calls post-load callbacks for the specified instance.
129: * <p>
130: * These include:
131: * <ul>
132: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
133: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
134: * </ul>
135: *
136: * @param instance The loaded instance
137: */
138: public void invokePostLoadCallbacks(Object instance) {
139: invokeCallbacks(instance, LifecycleEvent.POST_LOAD);
140: }
141:
142: /**
143: * Calls pre-update callbacks for the specified instance.
144: * <p>
145: * These include:
146: * <ul>
147: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
148: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
149: * </ul>
150: *
151: * @param instance The updated instance
152: */
153: public void invokePreUpdateCallbacks(Object instance) {
154: invokeCallbacks(instance, LifecycleEvent.PRE_UPDATE);
155: }
156:
157: /**
158: * Calls post-update callbacks for the specified instance.
159: * <p>
160: * These include:
161: * <ul>
162: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
163: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
164: * </ul>
165: *
166: * @param instance The updated instance
167: */
168: public void invokePostUpdateCallbacks(Object instance) {
169: invokeCallbacks(instance, LifecycleEvent.POST_UPDATE);
170: }
171:
172: /**
173: * Calls pre-remove callbacks for the specified instance.
174: * <p>
175: * These include:
176: * <ul>
177: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
178: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
179: * </ul>
180: *
181: * @param instance The instance for removal
182: */
183: public void invokePreRemoveCallbacks(Object instance) {
184: invokeCallbacks(instance, LifecycleEvent.PRE_REMOVE);
185: }
186:
187: /**
188: * Calls post-remove callbacks for the specified instance.
189: * <p>
190: * These include:
191: * <ul>
192: * <li>Lifecycle callbacks declared by the entity or its managed ancestors,</li>
193: * <li>Callbacks declared in classes referenced by {@link EntityListeners} on the entity or its ancestors.</li>
194: * </ul>
195: *
196: * @param instance The removed instance
197: */
198: public void invokePostRemoveCallbacks(Object instance) {
199: invokeCallbacks(instance, LifecycleEvent.POST_REMOVE);
200: }
201:
202: void setParent(EntityLifecycleListenerManager parent) {
203: this.parent = parent;
204: }
205:
206: void addEntityListener(Object entityListener) {
207: assert entityListener != null;
208:
209: if (entityListeners == null) {
210: this.entityListeners = new ArrayList<>();
211: }
212: entityListeners.add(entityListener);
213: if (entityListenerCallbacks == null) {
214: this.entityListenerCallbacks = new HashMap<>();
215: }
216: entityListenerCallbacks.put(entityListener, new EnumMap<>(LifecycleEvent.class));
217: }
218:
219: void addLifecycleCallback(LifecycleEvent event, Method callback) {
220: assert event != null;
221: assert callback != null;
222:
223: lifecycleCallbacks.put(event, callback);
224: }
225:
226: Map<LifecycleEvent, Method> getLifecycleCallbacks() {
227: return Collections.unmodifiableMap(lifecycleCallbacks);
228: }
229:
230: boolean hasLifecycleCallback(LifecycleEvent event) {
231: return lifecycleCallbacks.containsKey(event);
232: }
233:
234: List<Object> getEntityListeners() {
235: return entityListeners != null ? Collections.unmodifiableList(entityListeners) : Collections.emptyList();
236: }
237:
238: Map<Object, Map<LifecycleEvent, Method>> getEntityListenerCallbacks() {
239: return entityListenerCallbacks != null ? Collections.unmodifiableMap(entityListenerCallbacks) :
240: Collections.emptyMap();
241: }
242:
243: void addEntityListenerCallback(Object listener, LifecycleEvent event, Method callback) {
244: assert listener != null;
245: assert event != null;
246: assert callback != null;
247: assert entityListenerCallbacks.containsKey(listener);
248:
249: entityListenerCallbacks.get(listener).put(event, callback);
250: }
251:
252: boolean hasEntityListenerCallback(Object listener, LifecycleEvent event) {
253: return entityListenerCallbacks != null && entityListenerCallbacks.containsKey(listener) &&
254: entityListenerCallbacks.get(listener).containsKey(event);
255: }
256: }