1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.bitrepository.integrityservice.web;
26
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Map;
37
38 import javax.ws.rs.Consumes;
39 import javax.ws.rs.DefaultValue;
40 import javax.ws.rs.FormParam;
41 import javax.ws.rs.GET;
42 import javax.ws.rs.POST;
43 import javax.ws.rs.Path;
44 import javax.ws.rs.Produces;
45 import javax.ws.rs.QueryParam;
46 import javax.ws.rs.WebApplicationException;
47 import javax.ws.rs.core.MediaType;
48 import javax.ws.rs.core.Response;
49 import javax.ws.rs.core.StreamingOutput;
50
51 import org.bitrepository.common.utils.FileSizeUtils;
52 import org.bitrepository.common.utils.SettingsUtils;
53 import org.bitrepository.common.utils.TimeUtils;
54 import org.bitrepository.integrityservice.IntegrityServiceManager;
55 import org.bitrepository.integrityservice.cache.CollectionStat;
56 import org.bitrepository.integrityservice.cache.IntegrityModel;
57 import org.bitrepository.integrityservice.cache.PillarStat;
58 import org.bitrepository.integrityservice.cache.database.IntegrityIssueIterator;
59 import org.bitrepository.integrityservice.workflow.IntegrityCheckWorkflow;
60 import org.bitrepository.service.workflow.JobID;
61 import org.bitrepository.service.workflow.Workflow;
62 import org.bitrepository.service.workflow.WorkflowManager;
63 import org.bitrepository.service.workflow.WorkflowStatistic;
64 import org.json.JSONArray;
65 import org.json.JSONException;
66 import org.json.JSONObject;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 @Path("/IntegrityService")
71 public class RestIntegrityService {
72 private final Logger log = LoggerFactory.getLogger(getClass());
73 private IntegrityModel model;
74 private WorkflowManager workflowManager;
75
76 private final static String JSON_LIST_START = "[";
77 private final static String JSON_LIST_END = "]";
78 private final static String JSON_LIST_SEPERATOR = ",";
79 private final static String JSON_DELIMITER = "\"";
80
81 public RestIntegrityService() {
82 this.model = IntegrityServiceManager.getIntegrityModel();
83 this.workflowManager = IntegrityServiceManager.getWorkflowManager();
84 }
85
86
87
88
89
90
91
92
93 @GET
94 @Path("/getChecksumErrorFileIDs/")
95 @Produces(MediaType.APPLICATION_JSON)
96 public List<String> getChecksumErrors(
97 @QueryParam("collectionID") String collectionID,
98 @QueryParam("pillarID") String pillarID,
99 @QueryParam("pageNumber") int pageNumber,
100 @DefaultValue("100") @QueryParam("pageSize") int pageSize) {
101
102 int firstID = (pageNumber - 1) * pageSize;
103 int lastID = (pageNumber * pageSize) - 1;
104 List<String> ids = model.getFilesWithChecksumErrorsAtPillar(pillarID, firstID, lastID, collectionID);
105 return ids;
106 }
107
108
109
110
111
112
113
114
115 @GET
116 @Path("/getMissingFileIDs/")
117 @Produces(MediaType.APPLICATION_JSON)
118 public StreamingOutput getMissingFileIDs(
119 @QueryParam("collectionID") String collectionID,
120 @QueryParam("pillarID") String pillarID,
121 @QueryParam("pageNumber") int pageNumber,
122 @DefaultValue("100") @QueryParam("pageSize") int pageSize) {
123
124 int firstID = (pageNumber - 1) * pageSize;
125 int lastID = (pageNumber * pageSize) - 1;
126
127 final IntegrityIssueIterator it = model.getMissingFilesAtPillarByIterator(pillarID,
128 firstID, lastID, collectionID);
129
130 if(it != null) {
131 return new StreamingOutput() {
132 public void write(OutputStream output) throws IOException, WebApplicationException {
133 try {
134 boolean firstIssueWritten = false;
135 String issue;
136 output.write(JSON_LIST_START.getBytes());
137 while((issue = it.getNextIntegrityIssue()) != null) {
138 if(firstIssueWritten) {
139 output.write(JSON_LIST_SEPERATOR.getBytes());
140 }
141 String issueStr = JSON_DELIMITER + issue + JSON_DELIMITER;
142 output.write(issueStr.getBytes());
143 firstIssueWritten = true;
144 }
145 output.write(JSON_LIST_END.getBytes());
146 } catch (Exception e) {
147 throw new WebApplicationException(e);
148 } finally {
149 try {
150 if(it != null) {
151 it.close();
152 }
153 } catch (Exception e) {
154 log.error("Caught execption when closing IntegrityIssueIterator", e);
155 throw new WebApplicationException(e);
156 }
157 }
158 }
159 };
160 } else {
161 throw new WebApplicationException(Response.status(Response.Status.NO_CONTENT)
162 .entity("Failed to get missing files from database")
163 .type(MediaType.TEXT_PLAIN)
164 .build());
165 }
166 }
167
168
169
170
171
172
173
174
175 @GET
176 @Path("/getAllFileIDs/")
177 @Produces(MediaType.APPLICATION_JSON)
178 public List<String> getAllFileIDs(
179 @QueryParam("collectionID") String collectionID,
180 @QueryParam("pillarID") String pillarID,
181 @QueryParam("pageNumber") int pageNumber,
182 @DefaultValue("100") @QueryParam("pageSize") int pageSize) {
183
184 int firstID = (pageNumber - 1) * pageSize;
185 int lastID = (pageNumber * pageSize) - 1;
186
187 List<String> ids = model.getFilesOnPillar(pillarID, firstID, lastID, collectionID);
188 return ids;
189 }
190
191
192
193
194 @GET
195 @Path("/getIntegrityStatus/")
196 @Produces(MediaType.APPLICATION_JSON)
197 public String getIntegrityStatus(@QueryParam("collectionID") String collectionID) {
198 JSONArray array = new JSONArray();
199 List<String> pillars = SettingsUtils.getPillarIDsForCollection(collectionID);
200 Map<String, PillarStat> stats = new HashMap<String, PillarStat>();
201 for(PillarStat stat : model.getLatestPillarStats(collectionID)) {
202 if(pillars.contains(stat.getPillarID())) {
203 stats.put(stat.getPillarID(), stat);
204 }
205 }
206 for(String pillar : pillars) {
207 if(!stats.containsKey(pillar)) {
208 PillarStat emptyStat = new PillarStat(pillar, collectionID, 0L, 0L, 0L, 0L,
209 new Date(0), new Date(0));;
210 stats.put(pillar, emptyStat);
211 }
212 }
213 for(PillarStat stat : stats.values()) {
214 array.put(makeIntegrityStatusObj(stat));
215 }
216 return array.toString();
217 }
218
219
220
221
222 @GET
223 @Path("/getWorkflowSetup/")
224 @Produces(MediaType.APPLICATION_JSON)
225 public String getWorkflowSetup(@QueryParam("collectionID") String collectionID) {
226 try {
227 JSONArray array = new JSONArray();
228 for(JobID workflowID : workflowManager.getWorkflows(collectionID)) {
229 array.put(makeWorkflowSetupObj(workflowID));
230 }
231 return array.toString();
232 } catch (RuntimeException e) {
233 log.error("Failed to getWorkflowSetup ", e);
234 throw e;
235 }
236 }
237
238
239
240
241 @GET
242 @Path("/getWorkflowList/")
243 @Produces(MediaType.APPLICATION_JSON)
244 public List<String> getWorkflowList(@QueryParam("collectionID") String collectionID) {
245 List<String> workflowIDs = new LinkedList<String>();
246 for(JobID workflowID : workflowManager.getWorkflows(collectionID)) {
247 workflowIDs.add(workflowID.getWorkflowName());
248 }
249 return workflowIDs;
250 }
251
252
253
254
255 @GET
256 @Path("/getLatestIntegrityReport/")
257 @Produces(MediaType.TEXT_PLAIN)
258 public StreamingOutput getLatestIntegrityReport(@QueryParam("collectionID") String collectionID,
259 @QueryParam("workflowID") String workflowID) {
260 List<JobID> jobIDs = workflowManager.getWorkflows(collectionID);
261 for(JobID jobID : jobIDs) {
262 if(jobID.getWorkflowName().equals(workflowID)) {
263 Workflow workflow = workflowManager.getWorkflow(jobID);
264 if(workflow instanceof IntegrityCheckWorkflow) {
265 IntegrityCheckWorkflow integrityWorkflow = (IntegrityCheckWorkflow) workflow;
266 if(integrityWorkflow.getLatestIntegrityReport() != null) {
267 final File report;
268 try {
269 report = integrityWorkflow.getLatestIntegrityReport().getReport();
270 } catch (FileNotFoundException e) {
271 throw new WebApplicationException(e);
272
273 }
274 return new StreamingOutput() {
275 public void write(OutputStream output) throws IOException, WebApplicationException {
276 try {
277 int i;
278 byte[] data = new byte[4096];
279 FileInputStream is = new FileInputStream(report);
280 while((i = is.read(data)) >= 0) {
281 output.write(data, 0, i);
282 }
283 is.close();
284 } catch (Exception e) {
285 throw new WebApplicationException(e);
286 }
287 }
288 };
289 } else {
290 throw new WebApplicationException(Response.status(Response.Status.OK)
291 .entity("No integrity report for workflow " + workflowID + " for collection: "
292 + collectionID + " available yet")
293 .type(MediaType.TEXT_PLAIN)
294 .build());
295 }
296 }
297 }
298 }
299
300 throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
301 .entity("No integrity report for workflow: " + workflowID + " for collection: "
302 + collectionID + " found!")
303 .type(MediaType.TEXT_PLAIN)
304 .build());
305 }
306
307
308
309
310 @POST
311 @Path("/startWorkflow/")
312 @Consumes("application/x-www-form-urlencoded")
313 @Produces("text/html")
314 public String startWorkflow(@FormParam("workflowID") String workflowID,
315 @FormParam("collectionID") String collectionID) {
316 return workflowManager.startWorkflow(new JobID(workflowID, collectionID));
317 }
318
319
320
321
322 @GET
323 @Path("/getCollectionInformation/")
324 @Produces(MediaType.APPLICATION_JSON)
325 public String getCollectionInformation(@QueryParam("collectionID") String collectionID) {
326 JSONObject obj = new JSONObject();
327 List<CollectionStat> stats = model.getLatestCollectionStat(collectionID, 1);
328 Date lastIngest = model.getDateForNewestFileEntryForCollection(collectionID);
329 String lastIngestStr = lastIngest == null ? "No files ingested yet" : TimeUtils.shortDate(lastIngest);
330 Long collectionSize;
331 Long numberOfFiles;
332 if(stats == null || stats.isEmpty()) {
333 collectionSize = 0L;
334 numberOfFiles = 0L;
335 } else {
336 CollectionStat stat = stats.get(0);
337 collectionSize = stat.getDataSize();
338 numberOfFiles = stat.getFileCount();
339 }
340 try {
341 obj.put("lastIngest", lastIngestStr);
342 obj.put("collectionSize", FileSizeUtils.toHumanShort(collectionSize));
343 obj.put("numberOfFiles", numberOfFiles);
344 } catch (JSONException e) {
345 obj = (JSONObject) JSONObject.NULL;
346 }
347 return obj.toString();
348 }
349
350 private JSONObject makeIntegrityStatusObj(PillarStat stat) {
351 JSONObject obj = new JSONObject();
352 try {
353 obj.put("pillarID", stat.getPillarID());
354 obj.put("totalFileCount", stat.getFileCount());
355 obj.put("missingFilesCount", stat.getMissingFiles());
356 obj.put("checksumErrorCount", stat.getChecksumErrors());
357 return obj;
358 } catch (JSONException e) {
359 return (JSONObject) JSONObject.NULL;
360 }
361 }
362
363 private JSONObject makeWorkflowSetupObj(JobID workflowID) {
364 JSONObject obj = new JSONObject();
365 Workflow workflow = workflowManager.getWorkflow(workflowID);
366 WorkflowStatistic lastRunStatistic = workflowManager.getLastCompleteStatistics(workflowID);
367 try {
368 obj.put("workflowID", workflowID.getWorkflowName());
369 obj.put("workflowDescription", workflow.getDescription());
370 obj.put("nextRun", TimeUtils.shortDate(workflowManager.getNextScheduledRun(workflowID)));
371 if (lastRunStatistic == null) {
372 obj.put("lastRun", "Workflow hasn't finished a run yet");
373 obj.put("lastRunDetails", "Workflow hasn't finished a run yet");
374 } else {
375 obj.put("lastRun", TimeUtils.shortDate(lastRunStatistic.getFinish()));
376 obj.put("lastRunDetails", lastRunStatistic.getFullStatistics());
377 }
378 long runInterval = workflowManager.getRunInterval(workflowID);
379 String intervalString;
380 if (runInterval == -1 ) {
381 intervalString = "Never";
382 } else {
383 intervalString = TimeUtils.millisecondsToHuman(runInterval);
384 }
385 obj.put("executionInterval", intervalString);
386 obj.put("currentState", workflowManager.getCurrentStatistics(workflowID).getPartStatistics());
387 return obj;
388 } catch (JSONException e) {
389 return (JSONObject) JSONObject.NULL;
390 }
391 }
392 }