View Javadoc

1   /*
2    * #%L
3    * Bitrepository Audit Trail Service
4    * %%
5    * Copyright (C) 2010 - 2012 The State and University Library, The Royal Library and The State Archives, Denmark
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 2.1 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package org.bitrepository.audittrails.store;
23  
24  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.ACTOR_KEY;
25  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.ACTOR_NAME;
26  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.ACTOR_TABLE;
27  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_ACTOR_KEY;
28  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_AUDIT;
29  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_CONTRIBUTOR_KEY;
30  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_FILE_KEY;
31  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_INFORMATION;
32  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_OPERATION_ID;
33  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_FINGERPRINT;
34  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_OPERATION;
35  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_OPERATION_DATE;
36  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_SEQUENCE_NUMBER;
37  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.AUDITTRAIL_TABLE;
38  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.COLLECTION_ID;
39  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.COLLECTION_KEY;
40  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.COLLECTION_TABLE;
41  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.CONTRIBUTOR_ID;
42  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.CONTRIBUTOR_KEY;
43  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.CONTRIBUTOR_TABLE;
44  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.FILE_COLLECTION_KEY;
45  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.FILE_FILEID;
46  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.FILE_KEY;
47  import static org.bitrepository.audittrails.store.AuditDatabaseConstants.FILE_TABLE;
48  
49  import java.sql.PreparedStatement;
50  import java.util.ArrayList;
51  import java.util.Arrays;
52  import java.util.List;
53  
54  import org.bitrepository.common.ArgumentValidator;
55  import org.bitrepository.service.database.DBConnector;
56  import org.bitrepository.service.database.DatabaseUtils;
57  import org.slf4j.Logger;
58  import org.slf4j.LoggerFactory;
59  
60  /**
61   * Extractor for the audit trail events from the AuditTrailServiceDatabase.
62   * 
63   * The actual extraction is delegated to the class AuditEventIterator.
64   * As such any change in extraction model should be reflected in the AuditEventIterator. 
65   * For futher details @see {@link org.bitrepository.audittrails.store.AuditEventIterator}
66   * 
67   * 
68   * Order of extraction:
69   * FileId, ContributorId, SequenceNumber, SeqNumber, ActorName, Operation, OperationDate, 
70   * AuditTrail, Information, OperationID, Certificate fingerprint
71   */
72  public class AuditDatabaseExtractor {
73      /** The log.*/
74      private Logger log = LoggerFactory.getLogger(getClass());
75      
76      /** Position of the FileId in the extraction.*/
77      public static final int POSITION_FILE_ID = 1;
78      /** Position of the ContributorId in the extraction.*/
79      public static final int POSITION_CONTRIBUTOR_ID = 2;
80      /** Position of the SequenceNumber in the extraction.*/
81      public static final int POSITION_SEQUENCE_NUMBER = 3;
82      /** Position of the ActorName in the extraction.*/
83      public static final int POSITION_ACTOR_NAME = 4;
84      /** Position of the Operation in the extraction.*/
85      public static final int POSITION_OPERATION = 5;
86      /** Position of the OperationDate in the extraction.*/
87      public static final int POSITION_OPERATION_DATE = 6;
88      /** Position of the AuditTrail in the extraction.*/
89      public static final int POSITION_AUDIT_TRAIL = 7;
90      /** Position of the Information in the extraction.*/
91      public static final int POSITION_INFORMATION = 8;
92      /** Position of the OperationID in the extraction.*/
93      public static final int POSITION_OPERATION_ID = 9;
94      /** Position of the fingerprint in the extraction.*/
95      public static final int POSITION_FINGERPRINT = 10;
96      
97      /** The model containing the elements for the restriction.*/
98      private final ExtractModel model;
99      /** The connector to the database.*/
100     private final DBConnector dbConnector;
101     
102     /**
103      * Constructor.
104      * @param model The model for the restriction for the extraction from the database.
105      * @param dbConnector The connector to the database, where the audit trails are to be extracted.
106      */
107     public AuditDatabaseExtractor(ExtractModel model, DBConnector dbConnector) {
108         ArgumentValidator.checkNotNull(model, "ExtractModel model");
109         ArgumentValidator.checkNotNull(dbConnector, "DBConnector dbConnector");
110         
111         this.model = model;
112         this.dbConnector = dbConnector;
113     }
114     
115     /**
116      * Method to extract the requested audit trails
117      * @return {@link AuditEventIterator} Iterator for extracting the Audittrails 
118      */
119     public AuditEventIterator extractAuditEventsByIterator() {
120         String sql = createSelectString() + " FROM " + AUDITTRAIL_TABLE + joinWithFileTable() + joinWithActorTable() 
121                 + joinWithContributorTable() + createRestriction();
122         try {
123             log.debug("Creating prepared statement with sql '" + sql + "' and arguments '" 
124                     + Arrays.asList(extractArgumentsFromModel()) + " for AuditEventIterator");
125             PreparedStatement ps = DatabaseUtils.createPreparedStatement(dbConnector.getConnection(), 
126                     sql, extractArgumentsFromModel());
127             return new AuditEventIterator(ps);
128         } catch (Exception e) {
129             throw new IllegalStateException("Failed to retrieve the audit trails from the database", e);
130         }
131     }
132     
133     /**
134      * NOTE: This is where the position of the constants come into play. 
135      * E.g. POSITION_FILE_GUID = 1 refers to the first extracted element being the AUDITTRAIL_FILE_GUID.
136      * @return Creates the SELECT string for the retrieval of the audit events.
137      */
138     private String createSelectString() {
139         StringBuilder res = new StringBuilder();
140         
141         res.append("SELECT ");
142         res.append(FILE_TABLE + "." + FILE_FILEID + ", ");
143         res.append(CONTRIBUTOR_TABLE + "." + CONTRIBUTOR_ID + ", ");
144         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_SEQUENCE_NUMBER + ", ");
145         res.append(ACTOR_TABLE + "." + ACTOR_NAME + ", ");
146         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION + ", ");
147         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION_DATE + ", ");
148         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_AUDIT + ", ");
149         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_INFORMATION + ", ");
150         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION_ID + ", ");
151         res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_FINGERPRINT + " ");
152         
153         return res.toString();
154     }
155     
156     /**
157      * Joining the AuditTrail table with the File table.
158      * 
159      * @return The sql for joining the tables.
160      */
161     private String joinWithFileTable() {
162         return " JOIN " + FILE_TABLE + " ON " + AUDITTRAIL_TABLE + "." + AUDITTRAIL_FILE_KEY + " = " + FILE_TABLE + "."
163                 + FILE_KEY + " "; 
164     }
165 
166     /**
167      * Joining the AuditTrail table with the Actor table.
168      * 
169      * @return The sql for joining the tables.
170      */
171     private String joinWithActorTable() {
172         return " JOIN " + ACTOR_TABLE + " ON " + AUDITTRAIL_TABLE + "." + AUDITTRAIL_ACTOR_KEY + " = " + ACTOR_TABLE 
173                 + "." + ACTOR_KEY + " "; 
174     }
175     
176     /**
177      * Joining the AuditTrail table with the Contributor table.
178      * 
179      * @return The sql for joining the tables.
180      */
181     private String joinWithContributorTable() {
182         return " JOIN " + CONTRIBUTOR_TABLE + " ON " + AUDITTRAIL_TABLE + "." + AUDITTRAIL_CONTRIBUTOR_KEY + " = " 
183                 + CONTRIBUTOR_TABLE + "." + CONTRIBUTOR_KEY + " "; 
184     }
185     
186     /**
187      * Create the restriction part of the SQL statement for extracting the requested data from the database.
188      * @return The restriction, or empty string if no restrictions.
189      */
190     private String createRestriction() {
191         StringBuilder res = new StringBuilder();
192         
193         if(model.getFileId() != null) {
194             nextArgument(res);
195             res.append(FILE_TABLE + "."+ FILE_FILEID + " = ? ");
196         }
197 
198         if(model.getCollectionId() != null) {
199             nextArgument(res);
200             res.append(FILE_TABLE + "." + FILE_COLLECTION_KEY + " = ( SELECT " + COLLECTION_KEY + " FROM " 
201                     + COLLECTION_TABLE + " WHERE " + COLLECTION_ID + " = ? )");
202         }
203         
204         if(model.getContributorId() != null) {
205             nextArgument(res);
206             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_CONTRIBUTOR_KEY + " = ( SELECT " + CONTRIBUTOR_KEY 
207                     + " FROM " + CONTRIBUTOR_TABLE + " WHERE " + CONTRIBUTOR_ID + " = ? )");
208         }
209         
210         if(model.getMinSeqNumber() != null) {
211             nextArgument(res);
212             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_SEQUENCE_NUMBER + " >= ?");
213         }
214         
215         if(model.getMaxSeqNumber() != null) {
216             nextArgument(res);
217             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_SEQUENCE_NUMBER + " <= ?");
218         }
219         
220         if(model.getActorName() != null) {
221             nextArgument(res);
222             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_ACTOR_KEY + " = ( SELECT " + ACTOR_KEY + " FROM " 
223                     + ACTOR_TABLE + " WHERE " + ACTOR_NAME + " = ? )");
224         }
225         
226         if(model.getOperation() != null) {
227             nextArgument(res);
228             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION + " = ?");
229         }
230         
231         if(model.getStartDate() != null) {
232             nextArgument(res);
233             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION_DATE + " >= ?");
234         }
235         
236         if(model.getEndDate() != null) {
237             nextArgument(res);
238             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION_DATE + " <= ?");
239         }
240         
241         if(model.getFingerprint() != null) {
242             nextArgument(res);
243             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_FINGERPRINT + " = ?");
244         }
245         
246         if(model.getOperationID() != null) {
247             nextArgument(res);
248             res.append(AUDITTRAIL_TABLE + "." + AUDITTRAIL_OPERATION_ID + " = ?");
249         }
250         
251         return res.toString();
252     }
253     
254     /**
255      * Adds either ' AND ' or 'WHERE ' depending on whether it is the first restriction.
256      * @param res The StringBuilder where the restrictions are combined.
257      */
258     private void nextArgument(StringBuilder res) {
259         if(res.length() > 0) {
260             res.append(" AND ");
261         } else {
262             res.append(" WHERE ");
263         }            
264     }
265     
266     /**
267      * @return The list of elements in the model which are not null.
268      */
269     private Object[] extractArgumentsFromModel() {
270         List<Object> res = new ArrayList<Object>();
271         
272         if(model.getFileId() != null) {
273             res.add(model.getFileId());
274         }
275         
276         if(model.getCollectionId() != null) {
277             res.add(model.getCollectionId());
278         }
279         
280         if(model.getContributorId() != null) {
281             res.add(model.getContributorId());
282         }
283         
284         if(model.getMinSeqNumber() != null) {
285             res.add(model.getMinSeqNumber());
286         }
287         
288         if(model.getMaxSeqNumber() != null) {
289             res.add(model.getMaxSeqNumber());
290         }
291         
292         if(model.getActorName() != null) {
293             res.add(model.getActorName());
294         }
295         
296         if(model.getOperation() != null) {
297             res.add(model.getOperation().toString());
298         }
299         
300         if(model.getStartDate() != null) {
301             res.add(model.getStartDate());
302         }
303         
304         if(model.getEndDate() != null) {
305             res.add(model.getEndDate());
306         }
307         
308         if(model.getFingerprint() != null) {
309             res.add(model.getFingerprint());
310         }
311         
312         if(model.getOperationID() != null) {
313             res.add(model.getOperationID());
314         }
315         
316         return res.toArray();
317     }
318 }