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.preserver;
23  
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.net.URL;
28  import java.util.Date;
29  import java.util.HashMap;
30  import java.util.Map;
31  import java.util.Timer;
32  import java.util.TimerTask;
33  
34  import org.bitrepository.audittrails.store.AuditTrailStore;
35  import org.bitrepository.bitrepositoryelements.ChecksumDataForFileTYPE;
36  import org.bitrepository.bitrepositoryelements.ChecksumSpecTYPE;
37  import org.bitrepository.client.eventhandler.EventHandler;
38  import org.bitrepository.common.ArgumentValidator;
39  import org.bitrepository.common.exceptions.OperationFailedException;
40  import org.bitrepository.common.settings.Settings;
41  import org.bitrepository.common.utils.Base16Utils;
42  import org.bitrepository.common.utils.CalendarUtils;
43  import org.bitrepository.common.utils.ChecksumUtils;
44  import org.bitrepository.common.utils.FileUtils;
45  import org.bitrepository.common.utils.SettingsUtils;
46  import org.bitrepository.common.utils.TimeUtils;
47  import org.bitrepository.modify.putfile.BlockingPutFileClient;
48  import org.bitrepository.modify.putfile.PutFileClient;
49  import org.bitrepository.protocol.CoordinationLayerException;
50  import org.bitrepository.protocol.FileExchange;
51  import org.bitrepository.settings.referencesettings.AuditTrailPreservation;
52  import org.slf4j.Logger;
53  import org.slf4j.LoggerFactory;
54  
55  /**
56   * Handles the preservation of audit trails to a collection defined for the local repository.
57   * This means, that each set of audit trails will be preserved within its own collection.
58   */
59  public class LocalAuditTrailPreserver implements AuditTrailPreserver {
60      /** The log.*/
61      private Logger log = LoggerFactory.getLogger(getClass());
62      /** The audit trails store, where the audit trails can be extracted.*/
63      private final AuditTrailStore store;
64      /** The put file client for sending the resulting files. */
65      private final BlockingPutFileClient client;
66  
67      /** The timer for scheduling the preservation of audit trails.*/
68      private Timer timer;
69      /** The timertask for preserving the audit trails.*/
70      private AuditPreservationTimerTask auditTask = null;
71      /** The mapping between collection and the Audit trail packer for packing and compressing the audit trails.*/
72      Map<String, AuditPacker> auditPackers = new HashMap<String, AuditPacker>();
73      /** The preservationSettings for the local audit trail preserver.*/
74      private final AuditTrailPreservation preservationSettings;
75      /** The full settings (needed for checksum calculation) */
76      private final Settings settings;
77      /** The fileexchange to use for uploading files which should be put to the preservation collection */
78      private final FileExchange exchange;
79      
80      /**
81       * Constructor.
82       * @param settings The preservationSettings for the audit trail service.
83       * @param store The storage of the audit trails, which should be preserved.
84       * @param client The PutFileClient for putting the audit trail packages to the collection.
85       */
86      public LocalAuditTrailPreserver(Settings settings, AuditTrailStore store, PutFileClient client,
87                                      FileExchange exchange) {
88          ArgumentValidator.checkNotNull(settings, "Settings preservationSettings");
89          ArgumentValidator.checkNotNull(store, "AuditTrailStore store");
90          ArgumentValidator.checkNotNull(client, "PutFileClient client");
91          
92          this.settings = settings;
93          this.preservationSettings = settings.getReferenceSettings().getAuditTrailServiceSettings().getAuditTrailPreservation();
94          this.store = store;
95          this.client = new BlockingPutFileClient(client);
96          this.exchange = exchange;
97          for(String collectionID : SettingsUtils.getAllCollectionsIDs()) {
98              this.auditPackers.put(collectionID, new AuditPacker(store, preservationSettings, collectionID));
99          }
100     }
101     
102     @Override
103     public void start() {
104         if(timer != null) {
105             log.debug("Cancelling old timer.");
106             timer.cancel();
107         }
108         long preservationInterval = preservationSettings.getAuditTrailPreservationInterval();
109         long timerCheckInterval = preservationInterval/10;
110         log.info("Instantiating the preservation of audit trails every " +
111                 TimeUtils.millisecondsToHuman(preservationInterval) + ", starting in " +
112                 TimeUtils.millisecondsToHuman(timerCheckInterval));
113         timer = new Timer();
114         auditTask = new AuditPreservationTimerTask(preservationInterval);
115         timer.scheduleAtFixedRate(auditTask, timerCheckInterval, timerCheckInterval);
116     }
117 
118     @Override
119     public void close() {
120         if(timer != null) {
121             timer.cancel();
122         }
123     }
124 
125     @Override
126     public void preserveRepositoryAuditTrails() {
127         if(auditTask == null) {
128             log.info("preserving the audit trails ");
129         } else {
130             auditTask.resetTime();
131         }
132         for(String collectionID : SettingsUtils.getAllCollectionsIDs()) {
133             performAuditTrailPreservation(collectionID);
134         }
135     }
136     
137     /**
138      * Performs the audit trails preservation.
139      * Uses the AuditPacker to pack the audit trails in a file, then uploads the file to the default file-server, and
140      * finally use the PutFileClient to ingest the package into the collection.
141      * When the 'put' has completed the Store is updated with the newest preservation sequence numbers for the 
142      * contributors.
143      * @param collectionId The id of the collection whose audit trails should be preserved.
144      */
145     private synchronized void performAuditTrailPreservation(String collectionId) {
146         try {
147             File auditPackage = auditPackers.get(collectionId).createNewPackage();
148             URL url = uploadFile(auditPackage);
149             log.info("Uploaded the file '" + auditPackage + "' to '" + url.toExternalForm() + "'");
150             
151             ChecksumDataForFileTYPE checksumData = getValidationChecksumDataForFile(auditPackage);
152             
153             EventHandler eventHandler = new AuditPreservationEventHandler(
154                     auditPackers.get(collectionId).getSequenceNumbersReached(), store, collectionId);
155             client.putFile(preservationSettings.getAuditTrailPreservationCollection(), url,
156                     auditPackage.getName(), auditPackage.length(), checksumData, null, eventHandler,
157                     "Preservation of audit trails from the AuditTrail service.");
158 
159             log.debug("Cleanup of the uploaded audit trail package.");
160             FileUtils.delete(auditPackage);
161         } catch (IOException e) {
162             throw new CoordinationLayerException("Cannot perform the preservation of audit trails.", e);
163         } catch (OperationFailedException e) {
164             throw new CoordinationLayerException("Failed to put the packed audit trails.", e);
165         }
166     }
167     
168     /**
169      * Helper method to make a checksum for the putfile call. 
170      */
171     private ChecksumDataForFileTYPE getValidationChecksumDataForFile(File file) {
172         ChecksumSpecTYPE csSpec = ChecksumUtils.getDefault(settings);
173         String checksum = ChecksumUtils.generateChecksum(file, csSpec);
174 
175         ChecksumDataForFileTYPE res = new ChecksumDataForFileTYPE();
176         res.setCalculationTimestamp(CalendarUtils.getNow());
177         res.setChecksumSpec(csSpec);
178         res.setChecksumValue(Base16Utils.encodeBase16(checksum));
179 
180         return res;
181     } 
182     
183     /**
184      * Uploads the file to a server.
185      * @param file The file to upload.
186      * @return The URL to the file.
187      * @throws IOException If any issues occur with uploading the file.
188      */
189     private URL uploadFile(File file) throws IOException {
190         return exchange.uploadToServer(new FileInputStream(file), file.getName());
191     }
192     
193     /**
194      * Timer task for keeping track of the automated collecting of audit trails.
195      */
196     private class AuditPreservationTimerTask extends TimerTask {
197         /** The interval between running this timer task.*/
198         private final long interval;
199         /** The date for the next run.*/
200         private Date nextRun;
201         
202         /**
203          * Constructor.
204          * @param interval The interval between running this timer task.
205          */
206         private AuditPreservationTimerTask(long interval) {
207             this.interval = interval;
208             resetTime();
209         }
210         
211         /**
212          * Resets the date for next run.
213          */
214         private void resetTime() {
215             nextRun = new Date(System.currentTimeMillis() + interval);
216         }
217         
218         @Override
219         public void run() {
220             if(nextRun.getTime() < System.currentTimeMillis()) {
221                 try {
222                     log.debug("Time to preserve the audit trails.");
223                     preserveRepositoryAuditTrails();
224                 } catch (Exception e) {
225                     log.error("Caught exception while attempting to preserve audittrails", e);
226                 }
227                 resetTime();
228             }
229         }
230     }
231 }