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.integrityservice.workflow.step;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.bitrepository.bitrepositoryelements.FileAction;
34 import org.bitrepository.common.utils.SettingsUtils;
35 import org.bitrepository.integrityservice.cache.FileInfo;
36 import org.bitrepository.integrityservice.cache.IntegrityModel;
37 import org.bitrepository.integrityservice.cache.database.FileState;
38 import org.bitrepository.integrityservice.reports.IntegrityReporter;
39 import org.bitrepository.service.audit.AuditTrailManager;
40 import org.bitrepository.service.workflow.AbstractWorkFlowStep;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47 public class HandleChecksumValidationStep extends AbstractWorkFlowStep {
48
49 private Logger log = LoggerFactory.getLogger(getClass());
50
51 private final IntegrityModel store;
52
53 private final IntegrityReporter reporter;
54
55 private final AuditTrailManager auditManager;
56
57 public HandleChecksumValidationStep(IntegrityModel store, AuditTrailManager auditManager,
58 IntegrityReporter reporter) {
59 this.store = store;
60 this.auditManager = auditManager;
61 this.reporter = reporter;
62 }
63
64 @Override
65 public String getName() {
66 return "Handle files missing at some pillars.";
67 }
68
69
70
71
72 @Override
73 public synchronized void performStep() {
74 List<String> inconsistentFiles = store.getFilesWithInconsistentChecksums(reporter.getCollectionID());
75 List<String> collectionPillars = SettingsUtils.getPillarIDsForCollection(reporter.getCollectionID());
76 for(String file : inconsistentFiles) {
77 Collection<FileInfo> infos = store.getFileInfos(file, reporter.getCollectionID());
78 Set<String> checksums = getUniqueChecksums(infos);
79 if(checksums.size() > 1) {
80 createAuditForInconsistentChecksum(infos, file);
81 for(FileInfo info : infos) {
82 try {
83 reporter.reportChecksumIssue(file, info.getPillarId());
84 } catch (IOException e) {
85 log.error("Failed to report file: " + file + " as having a checksum issue", e);
86 }
87 }
88 store.setChecksumError(file, getPillarsFileExisting(infos), reporter.getCollectionID());
89 } else {
90 log.error("File with inconsistent checksums from SQL have apparently not inconsistency according to "
91 + "Java! This is a scenario, which must never occur!!!");
92 store.setChecksumAgreement(file, collectionPillars, reporter.getCollectionID());
93 }
94 }
95
96 store.setFilesWithConsistentChecksumToValid(reporter.getCollectionID());
97 }
98
99
100
101
102
103
104
105 private Set<String> getUniqueChecksums(Collection<FileInfo> infos) {
106 Set<String> checksums = new HashSet<String>();
107
108 for(FileInfo info : infos) {
109 if((info.getChecksum() != null) && (info.getFileState() == FileState.EXISTING)) {
110 checksums.add(info.getChecksum());
111 }
112 }
113
114 return checksums;
115 }
116
117
118
119
120
121
122 private List<String> getPillarsFileExisting(Collection<FileInfo> infos) {
123 List<String> res = new ArrayList<String>();
124
125 for(FileInfo info : infos) {
126 if(info.getFileState() == FileState.EXISTING) {
127 res.add(info.getPillarId());
128 }
129 }
130
131 return res;
132 }
133
134
135
136
137
138
139
140
141 private void createAuditForInconsistentChecksum(Collection<FileInfo> infos, String fileId) {
142 String auditText;
143 Map<String, List<String>> checksumMap = getChecksumMapping(infos);
144 String pillarId = findSingleInconsistentPillar(checksumMap);
145
146 if(pillarId != null) {
147 auditText = "Checksum inconsistency for the file '" + fileId + "' at collection '"
148 + reporter.getCollectionID() + "'. Possibly corrupt at pillar '" + pillarId
149 + "', since all the other pillars agree upon another checksum.";
150 } else {
151 auditText = "Checksum inconsistency for the file '" + fileId + "' at collection '"
152 + reporter.getCollectionID() + "'. The pillars have registered more than one unique "
153 + "checksum for the file.";
154 }
155 auditManager.addAuditEvent(reporter.getCollectionID(), fileId, "IntegrityService",
156 auditText, "IntegrityService validating the checksums.", FileAction.INCONSISTENCY);
157 }
158
159
160
161
162
163
164 private Map<String, List<String>> getChecksumMapping(Collection<FileInfo> infos) {
165 Map<String, List<String>> checksumMap = new HashMap<String, List<String>>();
166 for(FileInfo info : infos) {
167 List<String> pillarIdsForChecksum;
168 if(checksumMap.containsKey(info.getChecksum())) {
169 pillarIdsForChecksum = checksumMap.get(info.getChecksum());
170 } else {
171 pillarIdsForChecksum = new ArrayList<String>();
172 }
173 pillarIdsForChecksum.add(info.getPillarId());
174 checksumMap.put(info.getChecksum(), pillarIdsForChecksum);
175 }
176
177 return checksumMap;
178 }
179
180
181
182
183
184
185
186
187 private String findSingleInconsistentPillar(Map<String, List<String>> checksumMap) {
188 if(checksumMap.size() != 2) {
189 return null;
190 }
191 List<List<String>> pillarLists = new ArrayList<List<String>>(checksumMap.values());
192
193 if((pillarLists.get(0).size() > 1) && (pillarLists.get(1).size() > 1)) {
194 return null;
195 }
196 if((pillarLists.get(0).size() == 1) && (pillarLists.get(1).size() == 1)) {
197 return null;
198 }
199
200 if(pillarLists.get(0).size() == 1) {
201 return pillarLists.get(0).get(0);
202 } else {
203 return pillarLists.get(1).get(0);
204 }
205 }
206 }