1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.bitrepository.service.audit;
23
24 import static org.bitrepository.service.audit.AuditDatabaseConstants.ACTOR_GUID;
25 import static org.bitrepository.service.audit.AuditDatabaseConstants.ACTOR_NAME;
26 import static org.bitrepository.service.audit.AuditDatabaseConstants.ACTOR_TABLE;
27 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_ACTOR_GUID;
28 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_AUDIT;
29 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_FILE_GUID;
30 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_INFORMATION;
31 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_OPERATION;
32 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_OPERATION_DATE;
33 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_SEQUENCE_NUMBER;
34 import static org.bitrepository.service.audit.AuditDatabaseConstants.AUDITTRAIL_TABLE;
35 import static org.bitrepository.service.audit.AuditDatabaseConstants.FILE_COLLECTIONID;
36 import static org.bitrepository.service.audit.AuditDatabaseConstants.FILE_FILEID;
37 import static org.bitrepository.service.audit.AuditDatabaseConstants.FILE_GUID;
38 import static org.bitrepository.service.audit.AuditDatabaseConstants.FILE_TABLE;
39
40 import java.math.BigInteger;
41 import java.sql.Connection;
42 import java.sql.PreparedStatement;
43 import java.sql.ResultSet;
44 import java.util.ArrayList;
45 import java.util.Date;
46 import java.util.List;
47
48 import org.bitrepository.bitrepositoryelements.AuditTrailEvent;
49 import org.bitrepository.bitrepositoryelements.FileAction;
50 import org.bitrepository.common.ArgumentValidator;
51 import org.bitrepository.common.settings.Settings;
52 import org.bitrepository.common.utils.CalendarUtils;
53 import org.bitrepository.service.database.DBConnector;
54 import org.bitrepository.service.database.DatabaseManager;
55 import org.bitrepository.service.database.DatabaseUtils;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59
60
61
62
63
64 public class AuditTrailContributerDAO implements AuditTrailManager {
65
66 private Logger log = LoggerFactory.getLogger(getClass());
67
68 private DBConnector dbConnector;
69
70 private final String componentID;
71
72
73
74
75
76 public AuditTrailContributerDAO(Settings settings, DatabaseManager manager) {
77 ArgumentValidator.checkNotNull(settings, "settings");
78
79 this.componentID = settings.getComponentID();
80 this.dbConnector = manager.getConnector();
81
82 getConnection();
83 }
84
85
86
87
88
89
90 protected Connection getConnection() {
91 try {
92 Connection dbConnection = dbConnector.getConnection();
93 return dbConnection;
94 } catch (Exception e) {
95 throw new IllegalStateException("Could not instantiate the database", e);
96 }
97 }
98
99 @Override
100 public void addAuditEvent(String collectionId, String fileId, String actor, String info, String auditTrail, FileAction operation) {
101 ArgumentValidator.checkNotNull(collectionId, "String collectionId");
102 ArgumentValidator.checkNotNull(operation, "FileAction operation");
103 log.trace("Inserting an audit event for file '" + fileId + "', from actor '" + actor
104 + "' performing operation '" + operation + "', with the audit trail information '" + auditTrail + "'");
105
106 long fileGuid;
107 if(fileId == null || fileId.isEmpty()) {
108 fileGuid = retrieveFileGuid(collectionId, "null");
109 } else {
110 fileGuid = retrieveFileGuid(collectionId, fileId);
111 }
112 long actorGuid;
113 if(actor == null || actor.isEmpty()) {
114 actorGuid = retrieveActorGuid("null");
115 } else {
116 actorGuid = retrieveActorGuid(actor);
117 }
118
119 if(auditTrail == null) {
120 auditTrail = "";
121 }
122 if(info == null) {
123 info = "";
124 }
125
126 synchronized(this) {
127 String insertSql = "INSERT INTO " + AUDITTRAIL_TABLE + " ( " + AUDITTRAIL_FILE_GUID + " , "
128 + AUDITTRAIL_ACTOR_GUID + " , " + AUDITTRAIL_OPERATION + " , " + AUDITTRAIL_OPERATION_DATE + " , "
129 + AUDITTRAIL_AUDIT + " , " + AUDITTRAIL_INFORMATION + " ) VALUES ( ? , ? , ? , ? , ? , ? )";
130 DatabaseUtils.executeStatement(dbConnector, insertSql, fileGuid, actorGuid, operation.toString(),
131 new Date(), auditTrail, info);
132 }
133 }
134
135 @Override
136 public AuditTrailDatabaseResults getAudits(String collectionId, String fileId, Long minSeqNumber,
137 Long maxSeqNumber, Date minDate, Date maxDate, Long maxNumberOfResults) {
138 return extractEvents(new AuditTrailExtractor(collectionId, fileId, minSeqNumber, maxSeqNumber, minDate,
139 maxDate), maxNumberOfResults);
140 }
141
142
143
144
145
146 public Long extractLargestSequenceNumber() {
147 String sql = "SELECT " + AUDITTRAIL_SEQUENCE_NUMBER + " FROM " + AUDITTRAIL_TABLE + " ORDER BY "
148 + AUDITTRAIL_SEQUENCE_NUMBER + " DESC";
149
150 try {
151 PreparedStatement ps = null;
152 ResultSet res = null;
153 Connection conn = null;
154 try {
155 conn = getConnection();
156 ps = DatabaseUtils.createPreparedStatement(conn, sql, new Object[0]);
157 res = ps.executeQuery();
158 if(!res.next()) {
159 return 0L;
160 }
161 return res.getLong(1);
162 } finally {
163 if(res != null) {
164 res.close();
165 }
166 if(ps != null) {
167 ps.close();
168 }
169 if(conn != null) {
170 conn.close();
171 }
172 }
173 } catch (Exception e) {
174 throw new IllegalStateException("Could not use SQL query '" + sql
175 + "' for retrieving the largest sequence number", e);
176
177 }
178 }
179
180
181
182
183
184
185
186 private AuditTrailDatabaseResults extractEvents(AuditTrailExtractor extractor, Long maxNumberOfResults) {
187
188 final int sequencePosition = 1;
189 final int fileGuidPosition = 2;
190 final int actorPosition = 3;
191 final int actionDatePosition = 4;
192 final int operationPosition = 5;
193 final int auditTrailInformationPosition = 6;
194 final int infoPosition = 7;
195
196 String sql = "SELECT " + AUDITTRAIL_SEQUENCE_NUMBER + ", " + AUDITTRAIL_FILE_GUID + " , "
197 + AUDITTRAIL_ACTOR_GUID + " , " + AUDITTRAIL_OPERATION_DATE + " , " + AUDITTRAIL_OPERATION + " , "
198 + AUDITTRAIL_AUDIT + " , " + AUDITTRAIL_INFORMATION + " FROM " + AUDITTRAIL_TABLE + " "
199 + extractor.createRestriction();
200
201 AuditTrailDatabaseResults res = new AuditTrailDatabaseResults();
202 try {
203 PreparedStatement ps = null;
204 ResultSet results = null;
205 Connection conn = null;
206 try {
207 conn = getConnection();
208 ps = DatabaseUtils.createPreparedStatement(conn, sql, extractor.getArguments());
209 results = ps.executeQuery();
210
211 int count = 0;
212 while(results.next() && (maxNumberOfResults == null || count < maxNumberOfResults)) {
213 count++;
214 AuditTrailEvent event = new AuditTrailEvent();
215
216 event.setSequenceNumber(BigInteger.valueOf(results.getLong(sequencePosition)));
217 event.setFileID(retrieveFileId(results.getLong(fileGuidPosition)));
218 event.setActorOnFile(retrieveActorName(results.getLong(actorPosition)));
219 event.setActionDateTime(CalendarUtils.getFromMillis(results.getTimestamp(actionDatePosition).getTime()));
220 event.setActionOnFile(FileAction.fromValue(results.getString(operationPosition)));
221 event.setAuditTrailInformation(results.getString(auditTrailInformationPosition));
222 event.setInfo(results.getString(infoPosition));
223 event.setReportingComponent(componentID);
224 res.addAuditTrailEvent(event);
225 }
226
227 if(maxNumberOfResults != null && count >= maxNumberOfResults) {
228 log.debug("More than the maximum {} results found.", maxNumberOfResults);
229 res.reportMoreResultsFound();
230 }
231 } finally {
232 if(res != null) {
233 results.close();
234 }
235 if(ps != null) {
236 ps.close();
237 }
238 if(conn != null) {
239 conn.close();
240 }
241 }
242 } catch (Exception e) {
243 throw new IllegalStateException("Could not extract the audit trails events.", e);
244 }
245
246 log.debug("Extracted audit trail events: {}", res);
247 return res;
248 }
249
250
251
252
253
254
255
256
257 private synchronized long retrieveFileGuid(String collectionId, String fileId) {
258 String sqlRetrieve = "SELECT " + FILE_GUID + " FROM " + FILE_TABLE + " WHERE " + FILE_FILEID + " = ? AND "
259 + FILE_COLLECTIONID + " = ?";
260
261 Long guid = DatabaseUtils.selectLongValue(dbConnector, sqlRetrieve, fileId, collectionId);
262
263 if(guid == null) {
264 log.debug("Inserting fileid '" + fileId + "' into the file table.");
265 String sqlInsert = "INSERT INTO " + FILE_TABLE + " ( " + FILE_FILEID + " , " + FILE_COLLECTIONID
266 + " ) VALUES ( ? , ? )";
267 DatabaseUtils.executeStatement(dbConnector, sqlInsert, fileId, collectionId);
268
269 guid = DatabaseUtils.selectLongValue(dbConnector, sqlRetrieve, fileId, collectionId);
270 }
271
272 return guid;
273 }
274
275
276
277
278
279
280 private String retrieveFileId(long fileGuid) {
281 String sqlRetrieve = "SELECT " + FILE_FILEID + " FROM " + FILE_TABLE + " WHERE " + FILE_GUID + " = ?";
282
283 return DatabaseUtils.selectStringValue(dbConnector, sqlRetrieve, fileGuid);
284 }
285
286
287
288
289
290
291
292 private synchronized long retrieveActorGuid(String actorName) {
293 String sqlRetrieve = "SELECT " + ACTOR_GUID + " FROM " + ACTOR_TABLE + " WHERE " + ACTOR_NAME + " = ?";
294
295 Long guid = DatabaseUtils.selectLongValue(dbConnector, sqlRetrieve, actorName);
296
297 if(guid == null) {
298 log.debug("Inserting actor '" + actorName + "' into the actor table.");
299 String sqlInsert = "INSERT INTO " + ACTOR_TABLE + " ( " + ACTOR_NAME + " ) VALUES ( ? )";
300 DatabaseUtils.executeStatement(dbConnector, sqlInsert, actorName);
301
302 guid = DatabaseUtils.selectLongValue(dbConnector, sqlRetrieve, actorName);
303 }
304
305 return guid;
306 }
307
308
309
310
311
312
313 private String retrieveActorName(long actorGuid) {
314 String sqlRetrieve = "SELECT " + ACTOR_NAME + " FROM " + ACTOR_TABLE + " WHERE " + ACTOR_GUID + " = ?";
315
316 return DatabaseUtils.selectStringValue(dbConnector, sqlRetrieve, actorGuid);
317 }
318
319
320
321
322 private class AuditTrailExtractor {
323
324 private Long fileGuid;
325
326 private Long minSeqNumber;
327
328 private Long maxSeqNumber;
329
330 private Date minDate;
331
332 private Date maxDate;
333
334
335
336
337
338
339
340
341
342
343 public AuditTrailExtractor(String collectionId, String fileId, Long minSeqNumber, Long maxSeqNumber, Date minDate,
344 Date maxDate) {
345 if(fileId == null) {
346 this.fileGuid = null;
347 } else {
348 this.fileGuid = retrieveFileGuid(collectionId, fileId);
349 }
350 this.minSeqNumber = minSeqNumber;
351 this.maxSeqNumber = maxSeqNumber;
352 this.minDate = minDate;
353 this.maxDate = maxDate;
354 }
355
356
357
358
359 public String createRestriction() {
360
361 if(fileGuid == null && minSeqNumber == null && maxSeqNumber == null && minDate == null && maxDate == null) {
362 return "";
363 }
364
365 StringBuilder res = new StringBuilder();
366
367 if(fileGuid != null) {
368 nextArgument(res);
369 res.append(AUDITTRAIL_FILE_GUID + " = ?");
370 }
371
372 if(minSeqNumber != null) {
373 nextArgument(res);
374 res.append(AUDITTRAIL_SEQUENCE_NUMBER + " >= ?");
375 }
376
377 if(maxSeqNumber != null) {
378 nextArgument(res);
379 res.append(AUDITTRAIL_SEQUENCE_NUMBER + " <= ?");
380 }
381
382 if(minDate != null) {
383 nextArgument(res);
384 res.append(AUDITTRAIL_OPERATION_DATE + " >= ?");
385 }
386
387 if(maxDate != null) {
388 nextArgument(res);
389 res.append(AUDITTRAIL_OPERATION_DATE + " <= ?");
390 }
391
392 return res.toString();
393 }
394
395
396
397
398
399 private void nextArgument(StringBuilder res) {
400 if(res.length() > 0) {
401 res.append(" AND ");
402 } else {
403 res.append("WHERE ");
404 }
405 }
406
407
408
409
410 public Object[] getArguments() {
411 List<Object> res = new ArrayList<Object>();
412 if(fileGuid != null) {
413 res.add(fileGuid);
414 }
415 if(minSeqNumber != null) {
416 res.add(minSeqNumber);
417 }
418 if(maxSeqNumber != null) {
419 res.add(maxSeqNumber);
420 }
421 if(minDate != null) {
422 res.add(minDate);
423 }
424 if(maxDate != null) {
425 res.add(maxDate);
426 }
427
428 return res.toArray();
429 }
430 }
431 }