0
# Event Handling
1
2
Comprehensive event system for monitoring database lifecycle, transaction events, and data changes with support for custom event listeners and transaction data inspection.
3
4
## Capabilities
5
6
### Transaction Event Listener
7
8
Interface for listening to transaction lifecycle events with before/after commit and rollback hooks.
9
10
```java { .api }
11
/**
12
* Listen to transaction lifecycle events
13
*/
14
public interface TransactionEventListener<T> {
15
16
/**
17
* Called before a transaction is committed
18
* @param data Transaction data containing changes
19
* @param transaction The transaction being committed
20
* @return State object passed to afterCommit/afterRollback
21
* @throws Exception to prevent commit and trigger rollback
22
*/
23
T beforeCommit(TransactionData data, Transaction transaction) throws Exception;
24
25
/**
26
* Called after a transaction is successfully committed
27
* @param data Transaction data containing changes
28
* @param state State object returned from beforeCommit
29
* @param transaction The committed transaction
30
*/
31
void afterCommit(TransactionData data, T state, Transaction transaction);
32
33
/**
34
* Called after a transaction is rolled back
35
* @param data Transaction data containing changes
36
* @param state State object returned from beforeCommit (may be null)
37
* @param transaction The rolled back transaction
38
*/
39
void afterRollback(TransactionData data, T state, Transaction transaction);
40
}
41
```
42
43
**Usage Examples:**
44
45
```java
46
import org.neo4j.graphdb.event.TransactionEventListener;
47
import org.neo4j.graphdb.event.TransactionData;
48
49
public class AuditTransactionListener implements TransactionEventListener<Long> {
50
51
@Override
52
public Long beforeCommit(TransactionData data, Transaction transaction) throws Exception {
53
long startTime = System.currentTimeMillis();
54
55
// Validate changes before commit
56
for (Node createdNode : data.createdNodes()) {
57
if (createdNode.hasLabel(Label.label("User"))) {
58
if (!createdNode.hasProperty("email")) {
59
throw new IllegalStateException("User nodes must have email property");
60
}
61
}
62
}
63
64
// Log significant changes
65
if (data.createdNodes().iterator().hasNext() ||
66
data.deletedNodes().iterator().hasNext()) {
67
System.out.println("Transaction contains node changes");
68
}
69
70
return startTime;
71
}
72
73
@Override
74
public void afterCommit(TransactionData data, Long startTime, Transaction transaction) {
75
long duration = System.currentTimeMillis() - startTime;
76
77
// Log successful commit
78
System.out.println("Transaction committed in " + duration + "ms");
79
System.out.println(" Nodes created: " + count(data.createdNodes()));
80
System.out.println(" Nodes deleted: " + count(data.deletedNodes()));
81
System.out.println(" Relationships created: " + count(data.createdRelationships()));
82
System.out.println(" Relationships deleted: " + count(data.deletedRelationships()));
83
84
// Trigger external systems
85
notifyExternalSystems(data);
86
}
87
88
@Override
89
public void afterRollback(TransactionData data, Long startTime, Transaction transaction) {
90
if (startTime != null) {
91
long duration = System.currentTimeMillis() - startTime;
92
System.out.println("Transaction rolled back after " + duration + "ms");
93
}
94
}
95
96
private int count(Iterable<?> iterable) {
97
int count = 0;
98
for (Object ignored : iterable) count++;
99
return count;
100
}
101
102
private void notifyExternalSystems(TransactionData data) {
103
// Send notifications to external systems
104
// e.g., message queues, webhooks, etc.
105
}
106
}
107
108
// Register the listener
109
DatabaseManagementService managementService = // ... create service
110
GraphDatabaseService db = managementService.database("neo4j");
111
db.registerTransactionEventListener(new AuditTransactionListener());
112
```
113
114
### Database Event Listener
115
116
Interface for listening to database lifecycle events including creation, deletion, startup, and shutdown.
117
118
```java { .api }
119
/**
120
* Listen to database lifecycle events
121
*/
122
public interface DatabaseEventListener {
123
124
/**
125
* Called when a database is created
126
* @param eventContext Context information about the event
127
*/
128
void databaseCreate(DatabaseEventContext eventContext);
129
130
/**
131
* Called when a database is dropped
132
* @param eventContext Context information about the event
133
*/
134
void databaseDrop(DatabaseEventContext eventContext);
135
136
/**
137
* Called when a database is started
138
* @param eventContext Context information about the event
139
*/
140
void databaseStart(DatabaseEventContext eventContext);
141
142
/**
143
* Called when a database is shut down
144
* @param eventContext Context information about the event
145
*/
146
void databaseShutdown(DatabaseEventContext eventContext);
147
}
148
```
149
150
**Usage Examples:**
151
152
```java
153
import org.neo4j.graphdb.event.DatabaseEventListener;
154
import org.neo4j.graphdb.event.DatabaseEventContext;
155
156
public class DatabaseLifecycleListener implements DatabaseEventListener {
157
158
@Override
159
public void databaseCreate(DatabaseEventContext eventContext) {
160
String dbName = eventContext.getDatabaseName();
161
System.out.println("Database created: " + dbName);
162
163
// Initialize new database with default data
164
initializeDatabase(dbName);
165
166
// Log to audit system
167
auditLog("DATABASE_CREATED", dbName, eventContext.getEventData());
168
}
169
170
@Override
171
public void databaseDrop(DatabaseEventContext eventContext) {
172
String dbName = eventContext.getDatabaseName();
173
System.out.println("Database dropped: " + dbName);
174
175
// Cleanup external resources
176
cleanupExternalResources(dbName);
177
178
// Log to audit system
179
auditLog("DATABASE_DROPPED", dbName, eventContext.getEventData());
180
}
181
182
@Override
183
public void databaseStart(DatabaseEventContext eventContext) {
184
String dbName = eventContext.getDatabaseName();
185
System.out.println("Database started: " + dbName);
186
187
// Perform startup tasks
188
performStartupTasks(dbName);
189
190
// Register for monitoring
191
registerForMonitoring(dbName);
192
}
193
194
@Override
195
public void databaseShutdown(DatabaseEventContext eventContext) {
196
String dbName = eventContext.getDatabaseName();
197
System.out.println("Database shutting down: " + dbName);
198
199
// Perform cleanup tasks
200
performShutdownTasks(dbName);
201
202
// Unregister from monitoring
203
unregisterFromMonitoring(dbName);
204
}
205
206
private void initializeDatabase(String dbName) {
207
// Add default constraints, indexes, or seed data
208
}
209
210
private void cleanupExternalResources(String dbName) {
211
// Clean up external caches, connections, etc.
212
}
213
214
private void auditLog(String event, String dbName, Map<String, Object> data) {
215
// Log to external audit system
216
}
217
}
218
219
// Register the listener
220
DatabaseManagementService managementService = new DatabaseManagementServiceBuilder(dbPath)
221
.addDatabaseListener(new DatabaseLifecycleListener())
222
.build();
223
```
224
225
### Transaction Data Interface
226
227
Interface providing access to transaction change data including created, deleted, and modified entities.
228
229
```java { .api }
230
/**
231
* Access transaction change data
232
*/
233
public interface TransactionData {
234
235
/**
236
* Get nodes created in this transaction
237
* @return Iterable of created nodes
238
*/
239
Iterable<Node> createdNodes();
240
241
/**
242
* Get nodes deleted in this transaction
243
* @return Iterable of deleted nodes
244
*/
245
Iterable<Node> deletedNodes();
246
247
/**
248
* Get relationships created in this transaction
249
* @return Iterable of created relationships
250
*/
251
Iterable<Relationship> createdRelationships();
252
253
/**
254
* Get relationships deleted in this transaction
255
* @return Iterable of deleted relationships
256
*/
257
Iterable<Relationship> deletedRelationships();
258
259
/**
260
* Check if a node was created in this transaction
261
* @param node Node to check
262
* @return true if node was created
263
*/
264
boolean isCreated(Node node);
265
266
/**
267
* Check if a node was deleted in this transaction
268
* @param node Node to check
269
* @return true if node was deleted
270
*/
271
boolean isDeleted(Node node);
272
273
/**
274
* Check if a relationship was created in this transaction
275
* @param relationship Relationship to check
276
* @return true if relationship was created
277
*/
278
boolean isCreated(Relationship relationship);
279
280
/**
281
* Check if a relationship was deleted in this transaction
282
* @param relationship Relationship to check
283
* @return true if relationship was deleted
284
*/
285
boolean isDeleted(Relationship relationship);
286
287
/**
288
* Get assigned properties for a node
289
* @param node Node to get properties for
290
* @return Property container with assigned properties
291
*/
292
PropertyContainer assignedNodeProperties(Node node);
293
294
/**
295
* Get removed properties for a node
296
* @param node Node to get properties for
297
* @return Property container with removed properties
298
*/
299
PropertyContainer removedNodeProperties(Node node);
300
301
/**
302
* Get assigned properties for a relationship
303
* @param relationship Relationship to get properties for
304
* @return Property container with assigned properties
305
*/
306
PropertyContainer assignedRelationshipProperties(Relationship relationship);
307
308
/**
309
* Get removed properties for a relationship
310
* @param relationship Relationship to get properties for
311
* @return Property container with removed properties
312
*/
313
PropertyContainer removedRelationshipProperties(Relationship relationship);
314
315
/**
316
* Get assigned labels for a node
317
* @param node Node to get labels for
318
* @return Iterable of assigned labels
319
*/
320
Iterable<Label> assignedLabels(Node node);
321
322
/**
323
* Get removed labels for a node
324
* @param node Node to get labels for
325
* @return Iterable of removed labels
326
*/
327
Iterable<Label> removedLabels(Node node);
328
}
329
```
330
331
**Advanced Usage Examples:**
332
333
```java
334
public class ChangeTrackingListener implements TransactionEventListener<Map<String, Object>> {
335
336
@Override
337
public Map<String, Object> beforeCommit(TransactionData data, Transaction transaction) {
338
Map<String, Object> changesSummary = new HashMap<>();
339
340
// Track node changes
341
Map<String, Integer> nodeChanges = new HashMap<>();
342
343
// Count created nodes by label
344
for (Node node : data.createdNodes()) {
345
for (Label label : node.getLabels()) {
346
nodeChanges.merge("created_" + label.name(), 1, Integer::sum);
347
}
348
}
349
350
// Count deleted nodes by label
351
for (Node node : data.deletedNodes()) {
352
for (Label label : node.getLabels()) {
353
nodeChanges.merge("deleted_" + label.name(), 1, Integer::sum);
354
}
355
}
356
357
changesSummary.put("nodeChanges", nodeChanges);
358
359
// Track relationship changes
360
Map<String, Integer> relChanges = new HashMap<>();
361
362
for (Relationship rel : data.createdRelationships()) {
363
relChanges.merge("created_" + rel.getType().name(), 1, Integer::sum);
364
}
365
366
for (Relationship rel : data.deletedRelationships()) {
367
relChanges.merge("deleted_" + rel.getType().name(), 1, Integer::sum);
368
}
369
370
changesSummary.put("relationshipChanges", relChanges);
371
372
// Track property changes
373
int propertyChanges = 0;
374
375
// Check nodes for property changes
376
for (Node node : data.createdNodes()) {
377
PropertyContainer assigned = data.assignedNodeProperties(node);
378
for (String key : assigned.getPropertyKeys()) {
379
propertyChanges++;
380
}
381
}
382
383
// Check for property updates on existing nodes
384
// (This requires checking all nodes and comparing with removed properties)
385
386
changesSummary.put("totalPropertyChanges", propertyChanges);
387
388
return changesSummary;
389
}
390
391
@Override
392
public void afterCommit(TransactionData data, Map<String, Object> changesSummary,
393
Transaction transaction) {
394
395
// Log detailed changes
396
System.out.println("Transaction committed with changes:");
397
System.out.println(" Node changes: " + changesSummary.get("nodeChanges"));
398
System.out.println(" Relationship changes: " + changesSummary.get("relationshipChanges"));
399
System.out.println(" Property changes: " + changesSummary.get("totalPropertyChanges"));
400
401
// Send to monitoring system
402
sendToMonitoringSystem(changesSummary);
403
404
// Update search indexes or caches
405
updateExternalSystems(data);
406
}
407
408
@Override
409
public void afterRollback(TransactionData data, Map<String, Object> changesSummary,
410
Transaction transaction) {
411
System.out.println("Transaction rolled back - changes discarded");
412
if (changesSummary != null) {
413
System.out.println(" Would have applied: " + changesSummary);
414
}
415
}
416
417
private void sendToMonitoringSystem(Map<String, Object> changes) {
418
// Send metrics to monitoring system like Prometheus, DataDog, etc.
419
}
420
421
private void updateExternalSystems(TransactionData data) {
422
// Update search indexes, caches, message queues, etc.
423
}
424
}
425
```