From 44254a6d7fec97d6f0a80fa9f542bbaf493e54e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Fri, 2 Sep 2022 14:59:33 +0200 Subject: [PATCH 01/10] Created modal for downloading. Implemented necessary REST api calls. --- .../reports/IntegrityReportConstants.java | 8 ++ .../reports/IntegrityReportProvider.java | 54 +++++++++- .../web/RestIntegrityService.java | 96 ++++++++++++++--- .../src/main/webapp/download-modal.js | 100 ++++++++++++++++++ .../src/main/webapp/integrity-service.html | 21 +++- 5 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 bitrepository-webclient/src/main/webapp/download-modal.js diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportConstants.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportConstants.java index ed0e106d1..c348cf2d9 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportConstants.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportConstants.java @@ -21,6 +21,10 @@ */ package org.bitrepository.integrityservice.reports; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + /** * Class containing constants related to integrity reports */ @@ -59,4 +63,8 @@ public enum ReportPart { public static final String SECTION_HEADER_START_STOP = "========"; public static final String PILLAR_HEADER_START_STOP = "--------"; public static final String NO_ISSUE_HEADER_START_STOP = "++++++++"; + + public static Set getReportParts() { + return new HashSet<>(Arrays.asList(ReportPart.values())); + } } diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java index 4371a25e4..e37452d23 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java @@ -63,6 +63,26 @@ public synchronized IntegrityReportReader getLatestIntegrityReportReader(String return reader; } + /** + * Get the latest integrity report of a collection, for a specific report part and specific pillar. + * + * @param collectionID The specific collectionID. + * @param pillarID The specific pillarID. + * @param reportPart The specific ReportPart. + * @return Returns the given report part {@link File} if it exists. + * @throws FileNotFoundException If no such report part can be found for the given pillar and collection. + */ + public synchronized File getIntegrityReportPart(String collectionID, String pillarID, String reportPart) + throws FileNotFoundException { + log.info("Trying to lookup the '{}' report on disk for collection '{}'", reportPart, collectionID); + File latestReportPart = getReportPartFromDisk(collectionID, pillarID, reportPart); + if (latestReportPart != null) { + return latestReportPart; + } else { + throw new FileNotFoundException("Could not find latest integrity report"); + } + } + /** * Register the latest integrity report for a given collection * @@ -75,7 +95,7 @@ public synchronized void setLatestReport(String collectionID, File reportDir) { private File getLatestReportFromDisk(String collectionID) { File collectionReports = new File(reportsDir, collectionID); - log.info("Looking for latest report dir in {}", collectionReports); + log.info("Looking for latest report dir in '{}'", collectionReports); File[] reports = collectionReports.listFiles(File::isDirectory); long lastModification = Long.MIN_VALUE; File latestReport = null; @@ -87,7 +107,37 @@ private File getLatestReportFromDisk(String collectionID) { latestReport = reportDir; lastModification = latestReport.lastModified(); } else { - log.debug("Candidate report dir {} had no report file", reportDir); + log.debug("Candidate report dir '{}' had no report file", reportDir); + } + } + } + + return latestReport; + } + + /** + * Returns the latest report part for the given collection and pillar. + * + * @param collectionID The collection ID. + * @param pillarID The pillar ID. + * @param reportPart The wanted report part as {@link String}. + * @return Returns a {@link File} containing the latest report part for the given collection and pillar if such a file exists. + */ + private File getReportPartFromDisk(String collectionID, String pillarID, String reportPart) { + File collectionReports = new File(reportsDir, collectionID); + log.info("Looking for latest report dir in '{}'", collectionReports); + File[] reports = collectionReports.listFiles(File::isDirectory); + long lastModification = Long.MIN_VALUE; + File latestReport = null; + assert reports != null; + for (File reportDir : reports) { + if (reportDir.lastModified() > lastModification) { + File reportFile = new File(reportDir, reportPart + "-" + pillarID); + if (reportFile.exists()) { + latestReport = reportFile; + lastModification = latestReport.lastModified(); + } else { + log.debug("Report dir '{}' had no '{}'-report for pillar '{}'", reportDir, reportPart, pillarID); } } } diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java index 5eb7b31eb..eb2a29b7e 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java @@ -34,6 +34,7 @@ import org.bitrepository.integrityservice.cache.IntegrityModel; import org.bitrepository.integrityservice.cache.PillarCollectionStat; import org.bitrepository.integrityservice.cache.database.IntegrityIssueIterator; +import org.bitrepository.integrityservice.reports.IntegrityReportConstants; import org.bitrepository.integrityservice.reports.IntegrityReportConstants.ReportPart; import org.bitrepository.integrityservice.reports.IntegrityReportProvider; import org.bitrepository.integrityservice.reports.IntegrityReportReader; @@ -61,6 +62,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.OutputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Date; @@ -69,6 +71,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; @Path("/IntegrityService") @@ -324,6 +327,65 @@ public List getWorkflowList( return workflowIDs; } + /** + * Gets a {@link HashMap} with key {@link String} representing the {@link ReportPart} and value {@link List} of {@link String}s + * representing + * which pillars have a file for the given report part. + * {@link ReportPart} + * + * @param collectionID The collection ID for which the look at. + * @return {@link HashMap} mapping {@link ReportPart} to a {@link List} of pillars. + */ + @GET + @Path("/getAvailableIntegrityReports") + @Produces(MediaType.APPLICATION_JSON) + public HashMap> getAvailableIntegrityReports( + @QueryParam("collectionID") + String collectionID) { + HashMap> availableIntegrityReports = new HashMap<>(); + List pillars = SettingsUtils.getPillarIDsForCollection(collectionID); + Set reportParts = IntegrityReportConstants.getReportParts(); + + for (String pillarID : pillars) { + List reportPartOnPillar = new ArrayList<>(); + for (ReportPart currentReportPart : reportParts) { + try { + getReportPart(currentReportPart, collectionID, pillarID, 0, Integer.MAX_VALUE); + reportPartOnPillar.add(currentReportPart.getPartName()); + } catch (FileNotFoundException e) { + log.debug(e.getMessage()); + } + } + availableIntegrityReports.put(pillarID, reportPartOnPillar); + } + + return availableIntegrityReports; + } + + /** + * Get the latest integrity report, or an error message telling no such report found. + */ + @GET + @Path("/getIntegrityReportPart") + @Produces(MediaType.TEXT_PLAIN) + public StreamingOutput getLatestIntegrityReport( + @QueryParam("collectionID") + String collectionID, + @QueryParam("pillarID") + String pillarID, + @QueryParam("reportPart") + String reportPart) { + final File reportPartFile; + try { + reportPartFile = integrityReportProvider.getIntegrityReportPart(collectionID, pillarID, reportPart); + } catch (FileNotFoundException e) { + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) + .entity(String.format(Locale.ROOT, "No '%s' report part for collection: '%s' and pillar: '%s' found!", reportPart, + collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); + } + return output -> streamFile(reportPartFile, output); + } + /** * Get the latest integrity report, or an error message telling no such report found. */ @@ -341,19 +403,7 @@ public StreamingOutput getLatestIntegrityReport( .entity(String.format(Locale.ROOT, "No integrity report for collection: '%s' found!", collectionID)) .type(MediaType.TEXT_PLAIN).build()); } - return output -> { - try { - int i; - byte[] data = new byte[4096]; - FileInputStream is = new FileInputStream(fullReport); - while ((i = is.read(data)) >= 0) { - output.write(data, 0, i); - } - is.close(); - } catch (Exception e) { - throw new WebApplicationException(e); - } - }; + return output -> streamFile(fullReport, output); } /** @@ -504,6 +554,26 @@ private int getOffset(int page, int pageSize) { return (page - 1) * pageSize; } + /** + * Streams the given file, allowing it to be downloaded on REST api call. + * + * @param file The {@link File} to stream. + * @param output The {@link OutputStream} to write the stream to. + */ + private void streamFile(File file, OutputStream output) { + try { + int i; + byte[] data = new byte[4096]; + FileInputStream is = new FileInputStream(file); + while ((i = is.read(data)) >= 0) { + output.write(data, 0, i); + } + is.close(); + } catch (Exception e) { + throw new WebApplicationException(e); + } + } + private void writeIntegrityStatusObject(PillarCollectionStat stat, JsonGenerator jg) throws IOException { jg.writeStartObject(); jg.writeObjectField("pillarID", stat.getPillarID()); diff --git a/bitrepository-webclient/src/main/webapp/download-modal.js b/bitrepository-webclient/src/main/webapp/download-modal.js new file mode 100644 index 000000000..a2cfc641f --- /dev/null +++ b/bitrepository-webclient/src/main/webapp/download-modal.js @@ -0,0 +1,100 @@ +/* + * #%L + * Bitrepository Webclient + * %% + * Copyright (C) 2010 - 2013 The State and University Library, The Royal Library and The State Archives, Denmark + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +function DownloadModal(collectionID, contentElement, url) { + this.url = url; + + this.getModal = function () { + $.getJSON(this.url, {}, function (json) { + // Create table + let html = ``; + + // Populate the header of the table. + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + + // Init table body + html += `` + // Populate the table body + html += getTableBody(json); + + html += ``; + html += ``; + html += ``; + + // Assign content + $(contentElement).html(html); + }).fail(function () { + let html = "
" + html += "Failed to load page"; + html += "
" + $(contentElement).html(html); + }); + }; + + function getTableBody(json) { + let html = ``; + let pillars = Object.keys(json); + + for (let i = 0; i < pillars.length; i++) { + html += ``; + // Pillar information + html += `${pillars[i]}`; + + // Integrity Information + html += getReportPartTD(json, pillars[i], "missingFile"); + html += getReportPartTD(json, pillars[i], "missingChecksum"); + html += getReportPartTD(json, pillars[i], "obsoleteChecksum"); + html += getReportPartTD(json, pillars[i], "checksumIssue"); + // TODO: Include deletedFiles + + html += ``; + } + + // TODO: Create download button that uses "/getIntegrityReportPart" + return html; + } + + function getReportPartTD(json, pillarID, reportPart) { + let html = ""; + if (json[pillarID].includes(reportPart)) { + html += ``; + } else { + html += ``; + } + return html; + } + + function getTableFooter() { + // TODO: Footer with "Get all integrity reports" checkbox. + let footer = ""; + footer += ""; + return footer; + } +} diff --git a/bitrepository-webclient/src/main/webapp/integrity-service.html b/bitrepository-webclient/src/main/webapp/integrity-service.html index 7cbc312f2..1bf2dd80e 100644 --- a/bitrepository-webclient/src/main/webapp/integrity-service.html +++ b/bitrepository-webclient/src/main/webapp/integrity-service.html @@ -109,6 +109,7 @@

Modal header

+ @@ -117,6 +118,7 @@

Modal header

let pillarIntegrityStatuses = {}; let workflows = {}; let modal; + let downloadModal; let updatePageInterval; let nameMapper; let integrityServiceUrl; @@ -237,6 +239,16 @@

Modal header

} } + function showDownloadModal(integrityURL) { + return function () { + downloadModal = new DownloadModal(getCollectionID(), "#modalBody", integrityURL); + $("#modalLabel").html("Select Reports to Download"); + $("#modalBody").html("

Loading

"); + downloadModal.getModal(); + $("#modalDialog").modal('show'); + } + } + function getBodyContext(id, type) { let context = {}; context.url = integrityServiceUrl + "/integrity/IntegrityService/"; @@ -378,10 +390,11 @@

Modal header

function collectionChanged(collectionID) { clearContent(); $("#integrityLegend").html("Integrity information for collection " + nameMapper.getName(collectionID)); - let reportUrl = `${integrityServiceUrl}/integrity/IntegrityService/getLatestIntegrityReport - ?collectionID=${collectionID}&workflowID=CompleteIntegrityCheck`; - $("#integrityReportGetter").html( - `Get latest integrity report`); + + let reportUrl = `${integrityServiceUrl}/integrity/IntegrityService/getAvailableIntegrityReports?collectionID=${getCollectionID()}`; + $("#integrityReportGetter").html(`Download latest integrity reports`).on("click", + showDownloadModal(reportUrl)); + clearInterval(updatePageInterval); loadWorkflows(); getCollectionInformation(collectionID); From 5b5313ce4d46f7e7c8814502fac301ecc8a48e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Fri, 2 Sep 2022 16:27:13 +0200 Subject: [PATCH 02/10] Gives ERROR 500. --- .../web/RestIntegrityService.java | 109 +++++++++++++----- .../src/main/webapp/download-modal.js | 9 +- .../src/main/webapp/integrity-service.html | 2 +- 3 files changed, 85 insertions(+), 35 deletions(-) diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java index eb2a29b7e..3f858312e 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java @@ -58,10 +58,13 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.ArrayList; @@ -74,6 +77,10 @@ import java.util.Set; import java.util.stream.Collectors; +import static javax.ws.rs.core.Response.ResponseBuilder; +import static javax.ws.rs.core.Response.Status; +import static javax.ws.rs.core.Response.status; + @Path("/IntegrityService") public class RestIntegrityService { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -113,14 +120,13 @@ public HashMap> getTotalFileIDs( if (it == null) { throw new WebApplicationException( - Response.status(Response.Status.NO_CONTENT).entity("Failed to get missing files from database") - .type(MediaType.TEXT_PLAIN).build()); + status(Status.NO_CONTENT).entity("Failed to get missing files from database").type(MediaType.TEXT_PLAIN).build()); } List iteratorAsList = StreamingTools.iteratorToList(it); if (iteratorAsList.isEmpty()) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity(String.format(Locale.ROOT, "No fileIDs found for collection: '%s' and pillar: '%s'", collectionID, pillarID)) + throw new WebApplicationException(status(Status.NOT_FOUND).entity( + String.format(Locale.ROOT, "No fileIDs found for collection: '%s' and pillar: '%s'", collectionID, pillarID)) .type(MediaType.TEXT_PLAIN).build()); } @@ -158,8 +164,8 @@ public HashMap> getMissingFileIDs( missingOnPillar = getReportPart(part, collectionID, pillarID, page, pageSize); output.put(pillarID, missingOnPillar); } catch (FileNotFoundException e) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity(String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", + throw new WebApplicationException(status(Status.NOT_FOUND).entity( + String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", part.getHumanString(), collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); } @@ -366,44 +372,83 @@ public HashMap> getAvailableIntegrityReports( * Get the latest integrity report, or an error message telling no such report found. */ @GET - @Path("/getIntegrityReportPart") + @Path("/getLatestIntegrityReport") @Produces(MediaType.TEXT_PLAIN) public StreamingOutput getLatestIntegrityReport( @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("reportPart") - String reportPart) { - final File reportPartFile; + String collectionID) { + final File fullReport; try { - reportPartFile = integrityReportProvider.getIntegrityReportPart(collectionID, pillarID, reportPart); + fullReport = integrityReportProvider.getLatestIntegrityReportReader(collectionID).getFullReport(); } catch (FileNotFoundException e) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity(String.format(Locale.ROOT, "No '%s' report part for collection: '%s' and pillar: '%s' found!", reportPart, - collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException(status(Status.NOT_FOUND).entity( + String.format(Locale.ROOT, "No integrity report for collection: '%s' found!", collectionID)).type(MediaType.TEXT_PLAIN) + .build()); } - return output -> streamFile(reportPartFile, output); + return output -> streamFile(fullReport, output); + } + + @GET + @Path("/getIntegrityReportsAsZIP") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response getIntegrityReportsAsZIP( + @QueryParam("collectionID") + String collectionID, + @QueryParam("reports") + List reports) { + String fileName = "IntegrityReports.zip"; + int bufferSize = 4096; + List files = new ArrayList<>(); + + for (String report : reports) { + String[] parts = report.split("-", 2); + files.add(getLatestIntegrityReportPartFile(collectionID, parts[0], parts[1])); + } + + ResponseBuilder response; + InputStream in; + try (FileInputStream fis = new FileInputStream(files.get(0))) { + in = new ByteArrayInputStream(fis.readAllBytes()); + FileOutputStream out = new FileOutputStream(fileName); + byte[] bytes = new byte[bufferSize]; + int i; + + while ((i = in.read(bytes)) >= 0) { + out.write(bytes, 0, i); + } + out.flush(); + out.close(); + response = Response.ok(out); + } catch (IOException e) { + throw new WebApplicationException(status(Status.NOT_FOUND).entity( + String.format(Locale.ROOT, "No integrity report for collection: '%s' and pillar: '%s' found!", collectionID, + "TODO")) + .type(MediaType.TEXT_PLAIN).build()); + } + response.header("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + response.type("application/zip"); + return response.build(); } /** * Get the latest integrity report, or an error message telling no such report found. + * + * @param collectionID The collection ID. + * @param pillarID The pillar ID. + * @param reportPart The report part. + * @return {@link StreamingOutput} of the report part for the given collection and pillar. */ - @GET - @Path("/getLatestIntegrityReport") - @Produces(MediaType.TEXT_PLAIN) - public StreamingOutput getLatestIntegrityReport( - @QueryParam("collectionID") - String collectionID) { - final File fullReport; + public File getLatestIntegrityReportPartFile(String collectionID, String reportPart, String pillarID) { + final File reportPartFile; try { - fullReport = integrityReportProvider.getLatestIntegrityReportReader(collectionID).getFullReport(); + reportPartFile = integrityReportProvider.getIntegrityReportPart(collectionID, pillarID, reportPart); } catch (FileNotFoundException e) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity(String.format(Locale.ROOT, "No integrity report for collection: '%s' found!", collectionID)) - .type(MediaType.TEXT_PLAIN).build()); + String errorMessage = String.format(Locale.ROOT, "No '%s' report part for collection: '%s' and pillar: '%s' found!", reportPart, + collectionID, pillarID); + log.error(errorMessage); + throw new WebApplicationException(status(Status.NOT_FOUND).entity(errorMessage).type(MediaType.TEXT_PLAIN).build()); } - return output -> streamFile(fullReport, output); + return reportPartFile; } /** @@ -489,8 +534,8 @@ private List getReportPartForPillar(ReportPart part, String collectionID try { reportPartContent = getReportPart(part, collectionID, pillarID, page, pageSize); } catch (FileNotFoundException e) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity(String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", + throw new WebApplicationException(status(Status.NOT_FOUND).entity( + String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", part.getHumanString(), collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); } return reportPartContent; diff --git a/bitrepository-webclient/src/main/webapp/download-modal.js b/bitrepository-webclient/src/main/webapp/download-modal.js index a2cfc641f..574eaa13b 100644 --- a/bitrepository-webclient/src/main/webapp/download-modal.js +++ b/bitrepository-webclient/src/main/webapp/download-modal.js @@ -22,9 +22,10 @@ function DownloadModal(collectionID, contentElement, url) { this.url = url; + this.collectionID = collectionID; this.getModal = function () { - $.getJSON(this.url, {}, function (json) { + $.getJSON(`${this.url}/getAvailableIntegrityReports?collectionID=${this.collectionID}`, {}, function (json) { // Create table let html = ``; @@ -46,6 +47,10 @@ function DownloadModal(collectionID, contentElement, url) { html += ``; html += ``; + + // Init download button + html += `
` + html += `Download` html += `
`; // Assign content @@ -84,7 +89,7 @@ function DownloadModal(collectionID, contentElement, url) { function getReportPartTD(json, pillarID, reportPart) { let html = ""; if (json[pillarID].includes(reportPart)) { - html += ``; + html += ``; } else { html += ``; } diff --git a/bitrepository-webclient/src/main/webapp/integrity-service.html b/bitrepository-webclient/src/main/webapp/integrity-service.html index 1bf2dd80e..fb199367c 100644 --- a/bitrepository-webclient/src/main/webapp/integrity-service.html +++ b/bitrepository-webclient/src/main/webapp/integrity-service.html @@ -391,7 +391,7 @@

Modal header

clearContent(); $("#integrityLegend").html("Integrity information for collection " + nameMapper.getName(collectionID)); - let reportUrl = `${integrityServiceUrl}/integrity/IntegrityService/getAvailableIntegrityReports?collectionID=${getCollectionID()}`; + let reportUrl = `${integrityServiceUrl}/integrity/IntegrityService`; $("#integrityReportGetter").html(`Download latest integrity reports`).on("click", showDownloadModal(reportUrl)); From 023f5818306a717f7d205b929c3b0299198623fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Fri, 2 Sep 2022 17:00:04 +0200 Subject: [PATCH 03/10] Can now download a single file, but need to combine files into a .zip file. --- .../web/RestIntegrityService.java | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java index 3f858312e..dfca7c314 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java @@ -58,13 +58,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.ArrayList; @@ -397,7 +394,6 @@ public Response getIntegrityReportsAsZIP( @QueryParam("reports") List reports) { String fileName = "IntegrityReports.zip"; - int bufferSize = 4096; List files = new ArrayList<>(); for (String report : reports) { @@ -406,27 +402,24 @@ public Response getIntegrityReportsAsZIP( } ResponseBuilder response; - InputStream in; - try (FileInputStream fis = new FileInputStream(files.get(0))) { - in = new ByteArrayInputStream(fis.readAllBytes()); - FileOutputStream out = new FileOutputStream(fileName); - byte[] bytes = new byte[bufferSize]; - int i; + response = Response.ok(files.get(0)); + //response.type("application/zip"); + response.header("Content-Disposition", "attachment; filename=" + fileName); + //TODO: Is downloadable, but needs to make all of the files into a Zip. +// try { +// FileOutputStream out = new FileOutputStream(fileName); +// streamFile(files.get(0), out); +// response = Response.ok(out); +// response.type("application/zip"); +// response.header("Content-Disposition", "attachment; filename=" + fileName); +// out.flush(); +// out.close(); +// } catch (IOException e) { +// throw new WebApplicationException(status(Status.INTERNAL_SERVER_ERROR).entity("Something went wrong when trying to write +// file.") +// .type(MediaType.TEXT_PLAIN).build()); +// } - while ((i = in.read(bytes)) >= 0) { - out.write(bytes, 0, i); - } - out.flush(); - out.close(); - response = Response.ok(out); - } catch (IOException e) { - throw new WebApplicationException(status(Status.NOT_FOUND).entity( - String.format(Locale.ROOT, "No integrity report for collection: '%s' and pillar: '%s' found!", collectionID, - "TODO")) - .type(MediaType.TEXT_PLAIN).build()); - } - response.header("Content-Disposition", "attachment; filename=\"" + fileName + "\""); - response.type("application/zip"); return response.build(); } From e14505c12aaad4eac87d2b7147b4ca3377b4f635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Fri, 23 Sep 2022 15:26:26 +0200 Subject: [PATCH 04/10] Can now download the full report including any selected specific reports. --- .../web/RestIntegrityService.java | 46 ++++++++++-------- .../src/main/webapp/download-modal.js | 47 ++++++++++++++----- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java index dfca7c314..19d411c40 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -73,6 +74,8 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import static javax.ws.rs.core.Response.ResponseBuilder; import static javax.ws.rs.core.Response.Status; @@ -394,31 +397,36 @@ public Response getIntegrityReportsAsZIP( @QueryParam("reports") List reports) { String fileName = "IntegrityReports.zip"; - List files = new ArrayList<>(); + HashMap files = new HashMap<>(); for (String report : reports) { String[] parts = report.split("-", 2); - files.add(getLatestIntegrityReportPartFile(collectionID, parts[0], parts[1])); + files.put(report, getLatestIntegrityReportPartFile(collectionID, parts[0], parts[1])); } - ResponseBuilder response; - response = Response.ok(files.get(0)); - //response.type("application/zip"); + StreamingOutput streamingOutput = output -> { + ZipOutputStream zipOut = new ZipOutputStream(output); + // Add the full integrity report to the hashmap + files.put("report", integrityReportProvider.getLatestIntegrityReportReader(collectionID).getFullReport()); + + // Zip each file in the files hashmap + files.forEach((key, value) -> { + try { + zipOut.putNextEntry(new ZipEntry(key)); + zipOut.write(Files.readAllBytes(value.toPath())); + zipOut.flush(); + } catch (IOException e) { + throw new WebApplicationException( + status(Status.INTERNAL_SERVER_ERROR).entity("Something went wrong when trying to zip the file " + key + ".") + .type(MediaType.TEXT_PLAIN).build()); + } + }); + zipOut.close(); + }; + ResponseBuilder response = Response.ok(); + response.type("application/zip"); response.header("Content-Disposition", "attachment; filename=" + fileName); - //TODO: Is downloadable, but needs to make all of the files into a Zip. -// try { -// FileOutputStream out = new FileOutputStream(fileName); -// streamFile(files.get(0), out); -// response = Response.ok(out); -// response.type("application/zip"); -// response.header("Content-Disposition", "attachment; filename=" + fileName); -// out.flush(); -// out.close(); -// } catch (IOException e) { -// throw new WebApplicationException(status(Status.INTERNAL_SERVER_ERROR).entity("Something went wrong when trying to write -// file.") -// .type(MediaType.TEXT_PLAIN).build()); -// } + response.entity(streamingOutput); return response.build(); } diff --git a/bitrepository-webclient/src/main/webapp/download-modal.js b/bitrepository-webclient/src/main/webapp/download-modal.js index 574eaa13b..49cdf3ec9 100644 --- a/bitrepository-webclient/src/main/webapp/download-modal.js +++ b/bitrepository-webclient/src/main/webapp/download-modal.js @@ -24,10 +24,14 @@ function DownloadModal(collectionID, contentElement, url) { this.url = url; this.collectionID = collectionID; - this.getModal = function () { - $.getJSON(`${this.url}/getAvailableIntegrityReports?collectionID=${this.collectionID}`, {}, function (json) { + this.getModal = function (integrityURL = this.url) { + $.getJSON(`${integrityURL}/getAvailableIntegrityReports?collectionID=${this.collectionID}`, {}, function (json) { + let html = `

`; + html += `Select the reports you wish to download. If none are selected, only the latest full integrity report will be downloaded.`; + html += `

`; + // Create table - let html = ``; + html += ``; // Populate the header of the table. html += ``; @@ -41,7 +45,7 @@ function DownloadModal(collectionID, contentElement, url) { html += ``; // Init table body - html += `` + html += ``; // Populate the table body html += getTableBody(json); @@ -49,16 +53,18 @@ function DownloadModal(collectionID, contentElement, url) { html += ``; // Init download button - html += `
` - html += `Download` + html += `
`; + let zipURL = `${integrityURL}/getIntegrityReportsAsZIP?collectionID=${collectionID}`; + html += `Download Reports`; html += `
`; - // Assign content + // Assign content and apply listener functions. $(contentElement).html(html); + updateDownloadLink(zipURL); }).fail(function () { - let html = "
" + let html = "
"; html += "Failed to load page"; - html += "
" + html += "
"; $(contentElement).html(html); }); }; @@ -77,6 +83,7 @@ function DownloadModal(collectionID, contentElement, url) { html += getReportPartTD(json, pillars[i], "missingChecksum"); html += getReportPartTD(json, pillars[i], "obsoleteChecksum"); html += getReportPartTD(json, pillars[i], "checksumIssue"); + // html += getReportPartTD(json, pillars[i], "deletedFile"); // TODO: Include deletedFiles html += ``; @@ -89,13 +96,31 @@ function DownloadModal(collectionID, contentElement, url) { function getReportPartTD(json, pillarID, reportPart) { let html = ""; if (json[pillarID].includes(reportPart)) { - html += ``; + html += ` + `; } else { - html += ``; + html += ``; } return html; } + function updateDownloadLink(zipURL) { + $("input:checkbox[name=report-checkbox]").on("change", function () { + $(".download-button").attr("href", function () { + return zipURL + getSelected(); + }) + }); + } + + function getSelected() { + let output = ""; + $("input:checkbox[name=report-checkbox]:checked").each(function () { + output += `&reports=${$(this).val()}`; + }); + + return output; + } + function getTableFooter() { // TODO: Footer with "Get all integrity reports" checkbox. let footer = ""; From fb00b079f9e5dba9031389c33645519c1cc65396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 13:38:01 +0200 Subject: [PATCH 05/10] Created a reload button for the download modal. Also created a 'select all' checkbox. --- .../src/main/webapp/download-modal.js | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/bitrepository-webclient/src/main/webapp/download-modal.js b/bitrepository-webclient/src/main/webapp/download-modal.js index 49cdf3ec9..3afaacbe7 100644 --- a/bitrepository-webclient/src/main/webapp/download-modal.js +++ b/bitrepository-webclient/src/main/webapp/download-modal.js @@ -24,12 +24,19 @@ function DownloadModal(collectionID, contentElement, url) { this.url = url; this.collectionID = collectionID; - this.getModal = function (integrityURL = this.url) { - $.getJSON(`${integrityURL}/getAvailableIntegrityReports?collectionID=${this.collectionID}`, {}, function (json) { - let html = `

`; + this.getModal = function () { + let self = this; + $.getJSON(`${self.url}/getAvailableIntegrityReports?collectionID=${self.collectionID}`, {}, function (json) { + let html = `

`; html += `Select the reports you wish to download. If none are selected, only the latest full integrity report will be downloaded.`; html += `

`; + // Create "select all" checkbox and "reload table" button. + html += `
`; + html += `Select all: `; + html += `🔄`; + html += `

`; + // Create table html += ``; @@ -54,20 +61,21 @@ function DownloadModal(collectionID, contentElement, url) { // Init download button html += `
`; - let zipURL = `${integrityURL}/getIntegrityReportsAsZIP?collectionID=${collectionID}`; + let zipURL = `${self.url}/getIntegrityReportsAsZIP?collectionID=${self.collectionID}`; html += `Download Reports`; html += `
`; // Assign content and apply listener functions. $(contentElement).html(html); updateDownloadLink(zipURL); + enableOnClickFunctionality(self); }).fail(function () { let html = "
"; html += "Failed to load page"; html += "
"; $(contentElement).html(html); }); - }; + } function getTableBody(json) { let html = ``; @@ -97,7 +105,7 @@ function DownloadModal(collectionID, contentElement, url) { let html = ""; if (json[pillarID].includes(reportPart)) { html += ``; + `; } else { html += ``; } @@ -105,11 +113,14 @@ function DownloadModal(collectionID, contentElement, url) { } function updateDownloadLink(zipURL) { - $("input:checkbox[name=report-checkbox]").on("change", function () { - $(".download-button").attr("href", function () { - return zipURL + getSelected(); - }) + $("a[class=download-button]").on("click", function (e) { + e.originalEvent.currentTarget.href = zipURL + getSelected(); }); + // $("input:checkbox[name=report-checkbox]").on("change", function () { + // $(".download-button").attr("href", function () { + // return zipURL + getSelected(); + // }) + // }); } function getSelected() { @@ -121,10 +132,25 @@ function DownloadModal(collectionID, contentElement, url) { return output; } - function getTableFooter() { - // TODO: Footer with "Get all integrity reports" checkbox. - let footer = ""; - footer += ""; - return footer; + function enableOnClickFunctionality(self) { + // On click refresh table + $("span#refresh").on("click", function () { + self.getModal(); + }); + + // On click either select all or deselect all + $("input:checkbox[name=select-all]").change(function () { + if (this.checked) { + changeAllCheckboxes(true); + } else { + changeAllCheckboxes(false); + } + }); + } + + function changeAllCheckboxes(bool) { + $("input:checkbox").each(function () { + $(this).prop("checked", bool); + }); } } From b6d826300ba992b0510038bed0d02815e23a2863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 13:49:47 +0200 Subject: [PATCH 06/10] Now also shows deletedFile reports. --- .../src/main/webapp/download-modal.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/bitrepository-webclient/src/main/webapp/download-modal.js b/bitrepository-webclient/src/main/webapp/download-modal.js index 3afaacbe7..4c3195782 100644 --- a/bitrepository-webclient/src/main/webapp/download-modal.js +++ b/bitrepository-webclient/src/main/webapp/download-modal.js @@ -47,7 +47,8 @@ function DownloadModal(collectionID, contentElement, url) { html += ``; html += ``; html += ``; - html += ``; + html += ``; + html += ``; html += ``; html += ``; @@ -91,13 +92,11 @@ function DownloadModal(collectionID, contentElement, url) { html += getReportPartTD(json, pillars[i], "missingChecksum"); html += getReportPartTD(json, pillars[i], "obsoleteChecksum"); html += getReportPartTD(json, pillars[i], "checksumIssue"); - // html += getReportPartTD(json, pillars[i], "deletedFile"); - // TODO: Include deletedFiles + html += getReportPartTD(json, pillars[i], "deletedFile"); html += ``; } - // TODO: Create download button that uses "/getIntegrityReportPart" return html; } @@ -116,11 +115,6 @@ function DownloadModal(collectionID, contentElement, url) { $("a[class=download-button]").on("click", function (e) { e.originalEvent.currentTarget.href = zipURL + getSelected(); }); - // $("input:checkbox[name=report-checkbox]").on("change", function () { - // $(".download-button").attr("href", function () { - // return zipURL + getSelected(); - // }) - // }); } function getSelected() { From 1b8e2b2eae38d0146156b373c3deed2d8ac6eeb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 14:30:03 +0200 Subject: [PATCH 07/10] Fixed a small TODO. --- .../audittrails/AuditTrailService.java | 15 ++++-- .../webservice/RestAuditTrailService.java | 53 +++++++++++++------ .../src/main/webapp/flot/jquery.flot.pie.js | 2 +- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java index 0f4fe3057..35b3a4b03 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java @@ -83,7 +83,7 @@ public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, A /** * Constructor for audit trail service with disabled preservation. - * + *

* See {@link #AuditTrailService(AuditTrailStore, AuditTrailCollector, AuditTrailPreserver, ContributorMediator, * Settings)} for param descriptions. */ @@ -119,9 +119,7 @@ public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date to } /** - * Collects all the newest audit trails from the given collection. - * TODO this currently calls all collections. It should only call a specified collection, which should be given - * as argument. + * Collects all the newest audit trails from all collections. */ public void collectAuditTrails() { for (org.bitrepository.settings.repositorysettings.Collection c @@ -130,6 +128,13 @@ public void collectAuditTrails() { } } + /** + * Collects all the newest audit trails from a specific collection. + */ + public void collectAuditTrails(String collectionID) { + collector.collectNewestAudits(collectionID); + } + /** * Get the list of {@link CollectorInfo} * @@ -151,7 +156,7 @@ public List getCollectorInfos() { * @return PreservationInfo or null if not enabled. */ public PreservationInfo getPreservationInfo() { - if (preserver == null ) { + if (preserver == null) { return null; } return preserver.getPreservationInfo(); diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java index 9fe47349f..6c7ff3a5a 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java @@ -44,6 +44,7 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -52,6 +53,7 @@ import java.sql.SQLException; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.TimeZone; @Path("/AuditTrailService") @@ -69,16 +71,27 @@ public RestAuditTrailService() { @Consumes("application/x-www-form-urlencoded") @Produces("application/json") public StreamingOutput queryAuditTrailEvents( - @FormParam("fromDate") String fromDate, - @FormParam("toDate") String toDate, - @FormParam("fileID") String fileID, - @FormParam("reportingComponent") String reportingComponent, - @FormParam("actor") String actor, - @FormParam("action") String action, - @FormParam("collectionID") String collectionID, - @FormParam("fingerprint") String fingerprint, - @FormParam("operationID") String operationID, - @DefaultValue("1000") @FormParam("maxAuditTrails") Integer maxResults) { + @FormParam("fromDate") + String fromDate, + @FormParam("toDate") + String toDate, + @FormParam("fileID") + String fileID, + @FormParam("reportingComponent") + String reportingComponent, + @FormParam("actor") + String actor, + @FormParam("action") + String action, + @FormParam("collectionID") + String collectionID, + @FormParam("fingerprint") + String fingerprint, + @FormParam("operationID") + String operationID, + @DefaultValue("1000") + @FormParam("maxAuditTrails") + Integer maxResults) { Date from = calendarUtils.makeStartDateObject(fromDate); Date to = calendarUtils.makeEndDateObject(toDate); @@ -120,11 +133,21 @@ public StreamingOutput queryAuditTrailEvents( } @POST - @Path("/collectAuditTrails/") + @Path("/collectAuditTrails") @Produces("text/html") public String collectAuditTrails() { service.collectAuditTrails(); - return "Started audit trails collection"; + return "Started audit trails collection."; + } + + @POST + @Path("/collectSpecificAuditTrail") + @Produces("text/html") + public String collectSpecificAuditTrail( + @QueryParam("collectionID") + String collectionID) { + service.collectAuditTrails(collectionID); + return String.format(Locale.ROOT, "Started collecting audit trails for collection: %s.", collectionID); } @GET @@ -142,9 +165,9 @@ public PreservationInfo getPreservationSchedule() { if (preservationInfo != null) { return preservationInfo; } else { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) - .entity("404: Preservation must be enabled in settings to use this endpoint") - .type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException( + Response.status(Response.Status.NOT_FOUND).entity("404: Preservation must be enabled in settings to use this endpoint.") + .type(MediaType.TEXT_PLAIN).build()); } } diff --git a/bitrepository-webclient/src/main/webapp/flot/jquery.flot.pie.js b/bitrepository-webclient/src/main/webapp/flot/jquery.flot.pie.js index ff06a92a6..2cecbbddc 100644 --- a/bitrepository-webclient/src/main/webapp/flot/jquery.flot.pie.js +++ b/bitrepository-webclient/src/main/webapp/flot/jquery.flot.pie.js @@ -613,7 +613,7 @@ More detail and specific examples can be found in the included HTML file. arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]], arrPoint = [x, y]; - // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? + // TODO: perhaps do some mathematical trickery here with the Y-coordinate to compensate for pie tilt? if (isPointInPoly(arrPoly, arrPoint)) { ctx.restore(); From be0a9e249bb0c388f2f29bc8eff0789fb2ba81ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 14:40:29 +0200 Subject: [PATCH 08/10] Small change to a

tag. --- .../audittrails/AuditTrailService.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java index 35b3a4b03..c2ccfd67c 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java @@ -83,15 +83,11 @@ public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, A /** * Constructor for audit trail service with disabled preservation. - *

+ *

* See {@link #AuditTrailService(AuditTrailStore, AuditTrailCollector, AuditTrailPreserver, ContributorMediator, * Settings)} for param descriptions. */ - public AuditTrailService( - AuditTrailStore store, - AuditTrailCollector collector, - ContributorMediator mediator, - Settings settings) { + public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, ContributorMediator mediator, Settings settings) { this(store, collector, null, mediator, settings); } @@ -110,20 +106,19 @@ public AuditTrailService( * @param operationID Restrict the results to only this operationID * @return an iterator to all AuditTrailEvents matching the criteria from the parameters */ - public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date toDate, String fileID, - String collectionID, String reportingComponent, String actor, - FileAction action, + public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date toDate, String fileID, String collectionID, + String reportingComponent, String actor, FileAction action, String fingerprint, String operationID) { - return store.getAuditTrailsByIterator(fileID, collectionID, reportingComponent, null, null, actor, action, - fromDate, toDate, fingerprint, operationID); + return store.getAuditTrailsByIterator(fileID, collectionID, reportingComponent, null, null, actor, action, fromDate, toDate, + fingerprint, operationID); } /** * Collects all the newest audit trails from all collections. */ public void collectAuditTrails() { - for (org.bitrepository.settings.repositorysettings.Collection c - : settings.getRepositorySettings().getCollections().getCollection()) { + for (org.bitrepository.settings.repositorysettings.Collection c : settings.getRepositorySettings().getCollections() + .getCollection()) { collector.collectNewestAudits(c.getID()); } } @@ -142,8 +137,8 @@ public void collectAuditTrails(String collectionID) { */ public List getCollectorInfos() { List infos = new ArrayList<>(); - for (org.bitrepository.settings.repositorysettings.Collection c - : settings.getRepositorySettings().getCollections().getCollection()) { + for (org.bitrepository.settings.repositorysettings.Collection c : settings.getRepositorySettings().getCollections() + .getCollection()) { infos.add(collector.getCollectorInfo(c.getID())); } From f923f98ef467f01a89ba6242dc1362c2117d54dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 14:41:37 +0200 Subject: [PATCH 09/10] Roll back clean-up. --- .../audittrails/AuditTrailService.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java index c2ccfd67c..df018b467 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/AuditTrailService.java @@ -87,7 +87,11 @@ public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, A * See {@link #AuditTrailService(AuditTrailStore, AuditTrailCollector, AuditTrailPreserver, ContributorMediator, * Settings)} for param descriptions. */ - public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, ContributorMediator mediator, Settings settings) { + public AuditTrailService( + AuditTrailStore store, + AuditTrailCollector collector, + ContributorMediator mediator, + Settings settings) { this(store, collector, null, mediator, settings); } @@ -106,19 +110,20 @@ public AuditTrailService(AuditTrailStore store, AuditTrailCollector collector, C * @param operationID Restrict the results to only this operationID * @return an iterator to all AuditTrailEvents matching the criteria from the parameters */ - public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date toDate, String fileID, String collectionID, - String reportingComponent, String actor, FileAction action, + public AuditEventIterator queryAuditTrailEventsByIterator(Date fromDate, Date toDate, String fileID, + String collectionID, String reportingComponent, String actor, + FileAction action, String fingerprint, String operationID) { - return store.getAuditTrailsByIterator(fileID, collectionID, reportingComponent, null, null, actor, action, fromDate, toDate, - fingerprint, operationID); + return store.getAuditTrailsByIterator(fileID, collectionID, reportingComponent, null, null, actor, action, + fromDate, toDate, fingerprint, operationID); } /** * Collects all the newest audit trails from all collections. */ public void collectAuditTrails() { - for (org.bitrepository.settings.repositorysettings.Collection c : settings.getRepositorySettings().getCollections() - .getCollection()) { + for (org.bitrepository.settings.repositorysettings.Collection c + : settings.getRepositorySettings().getCollections().getCollection()) { collector.collectNewestAudits(c.getID()); } } @@ -137,8 +142,8 @@ public void collectAuditTrails(String collectionID) { */ public List getCollectorInfos() { List infos = new ArrayList<>(); - for (org.bitrepository.settings.repositorysettings.Collection c : settings.getRepositorySettings().getCollections() - .getCollection()) { + for (org.bitrepository.settings.repositorysettings.Collection c + : settings.getRepositorySettings().getCollections().getCollection()) { infos.add(collector.getCollectorInfo(c.getID())); } From 97b148679a98ce1a1f14bcb80d1e51c9b1637983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20S=C3=B8by?= Date: Mon, 26 Sep 2022 16:15:55 +0200 Subject: [PATCH 10/10] Small cleanup. --- .../webservice/RestAuditTrailService.java | 56 +++--- .../audittrails/AuditTrailServiceTest.java | 58 +++--- .../reports/IntegrityReportProvider.java | 3 +- .../web/RestIntegrityService.java | 174 +++++++----------- .../java/org/bitrepository/pillar/Pillar.java | 4 +- 5 files changed, 123 insertions(+), 172 deletions(-) diff --git a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java index 6c7ff3a5a..348c3f417 100644 --- a/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java +++ b/bitrepository-audit-trail-service/src/main/java/org/bitrepository/audittrails/webservice/RestAuditTrailService.java @@ -70,35 +70,23 @@ public RestAuditTrailService() { @Path("/queryAuditTrailEvents/") @Consumes("application/x-www-form-urlencoded") @Produces("application/json") - public StreamingOutput queryAuditTrailEvents( - @FormParam("fromDate") - String fromDate, - @FormParam("toDate") - String toDate, - @FormParam("fileID") - String fileID, - @FormParam("reportingComponent") - String reportingComponent, - @FormParam("actor") - String actor, - @FormParam("action") - String action, - @FormParam("collectionID") - String collectionID, - @FormParam("fingerprint") - String fingerprint, - @FormParam("operationID") - String operationID, - @DefaultValue("1000") - @FormParam("maxAuditTrails") - Integer maxResults) { + public StreamingOutput queryAuditTrailEvents(@FormParam("fromDate") String fromDate, + @FormParam("toDate") String toDate, + @FormParam("fileID") String fileID, + @FormParam("reportingComponent") String reportingComponent, + @FormParam("actor") String actor, + @FormParam("action") String action, + @FormParam("collectionID") String collectionID, + @FormParam("fingerprint") String fingerprint, + @FormParam("operationID") String operationID, + @DefaultValue("1000") @FormParam("maxAuditTrails") Integer maxResults) { Date from = calendarUtils.makeStartDateObject(fromDate); Date to = calendarUtils.makeEndDateObject(toDate); final int maxAudits = maxResults; - final AuditEventIterator it = service.queryAuditTrailEventsByIterator(from, to, contentOrNull(fileID), collectionID, - contentOrNull(reportingComponent), contentOrNull(actor), filterAction(action), contentOrNull(fingerprint), - contentOrNull(operationID)); + final AuditEventIterator it = service.queryAuditTrailEventsByIterator(from, to, contentOrNull(fileID), + collectionID, contentOrNull(reportingComponent), contentOrNull(actor), filterAction(action), + contentOrNull(fingerprint), contentOrNull(operationID)); if (it != null) { return output -> { JsonFactory jf = new JsonFactory(); @@ -127,8 +115,9 @@ public StreamingOutput queryAuditTrailEvents( } }; } else { - throw new WebApplicationException(Response.status(Response.Status.NO_CONTENT).entity("Failed to get audit trails from database") - .type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException( + Response.status(Response.Status.NO_CONTENT).entity("Failed to get audit trails from database") + .type(MediaType.TEXT_PLAIN).build()); } } @@ -143,9 +132,7 @@ public String collectAuditTrails() { @POST @Path("/collectSpecificAuditTrail") @Produces("text/html") - public String collectSpecificAuditTrail( - @QueryParam("collectionID") - String collectionID) { + public String collectSpecificAuditTrail(@QueryParam("collectionID") String collectionID) { service.collectAuditTrails(collectionID); return String.format(Locale.ROOT, "Started collecting audit trails for collection: %s.", collectionID); } @@ -165,9 +152,9 @@ public PreservationInfo getPreservationSchedule() { if (preservationInfo != null) { return preservationInfo; } else { - throw new WebApplicationException( - Response.status(Response.Status.NOT_FOUND).entity("404: Preservation must be enabled in settings to use this endpoint.") - .type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND) + .entity("404: Preservation must be enabled in settings to use this endpoint.") + .type(MediaType.TEXT_PLAIN).build()); } } @@ -177,7 +164,8 @@ private void writeAuditResult(AuditTrailEvent event, JsonGenerator jg) throws IO jg.writeObjectField("reportingComponent", event.getReportingComponent()); jg.writeObjectField("actor", contentOrEmptyString(event.getActorOnFile())); jg.writeObjectField("action", event.getActionOnFile().toString()); - jg.writeObjectField("timeStamp", TimeUtils.shortDate(CalendarUtils.convertFromXMLGregorianCalendar(event.getActionDateTime()))); + jg.writeObjectField("timeStamp", + TimeUtils.shortDate(CalendarUtils.convertFromXMLGregorianCalendar(event.getActionDateTime()))); jg.writeObjectField("info", contentOrEmptyString(event.getInfo())); jg.writeObjectField("auditTrailInfo", contentOrEmptyString(event.getAuditTrailInformation())); jg.writeObjectField("fingerprint", contentOrEmptyString(event.getCertificateID())); diff --git a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java index 47e9e77a0..511377311 100644 --- a/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java +++ b/bitrepository-audit-trail-service/src/test/java/org/bitrepository/audittrails/AuditTrailServiceTest.java @@ -5,16 +5,16 @@ * Copyright (C) 2010 - 2012 The State and University Library, The Royal Library and The State Archives, Denmark * %% * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public + * + * You should have received a copy of the GNU General Lesser Public * License along with this program. If not, see * . * #L% @@ -54,35 +54,35 @@ import static org.mockito.Mockito.verify; public class AuditTrailServiceTest extends ExtendedTestCase { - /** The settings for the tests. Should be instantiated in the setup.*/ + /** The settings for the tests. Should be instantiated in the setup. */ Settings settings; - + public static final String TEST_COLLECTION = "dummy-collection"; public static final String DEFAULT_CONTRIBUTOR = "Contributor1"; private ThreadFactory threadFactory; - @BeforeClass (alwaysRun = true) + @BeforeClass(alwaysRun = true) public void setup() throws Exception { settings = TestSettingsProvider.reloadSettings("AuditTrailServiceUnderTest"); Collection c = settings.getRepositorySettings().getCollections().getCollection().get(0); settings.getRepositorySettings().getCollections().getCollection().clear(); c.setID(TEST_COLLECTION); settings.getRepositorySettings().getCollections().getCollection().add(c); - threadFactory = new DefaultThreadFactory(this.getClass().getSimpleName(),Thread.NORM_PRIORITY); + threadFactory = new DefaultThreadFactory(this.getClass().getSimpleName(), Thread.NORM_PRIORITY); } - + @Test(groups = {"unstable"}) public void auditTrailServiceTest() throws Exception { addDescription("Test the Audit Trail Service"); DatatypeFactory factory = DatatypeFactory.newInstance(); settings.getRepositorySettings().getGetAuditTrailSettings().getNonPillarContributorIDs().clear(); - settings.getRepositorySettings().getGetAuditTrailSettings().getNonPillarContributorIDs().add(DEFAULT_CONTRIBUTOR); + settings.getRepositorySettings().getGetAuditTrailSettings().getNonPillarContributorIDs() + .add(DEFAULT_CONTRIBUTOR); settings.getReferenceSettings().getAuditTrailServiceSettings() .setCollectAuditInterval(factory.newDuration(800)); settings.getReferenceSettings().getAuditTrailServiceSettings().setTimerTaskCheckInterval(100L); - settings.getReferenceSettings().getAuditTrailServiceSettings() - .setGracePeriod(factory.newDuration(800)); + settings.getReferenceSettings().getAuditTrailServiceSettings().setGracePeriod(factory.newDuration(800)); AuditTrailStore store = mock(AuditTrailStore.class); AuditTrailClient client = mock(AuditTrailClient.class); @@ -90,39 +90,37 @@ public void auditTrailServiceTest() throws Exception { ContributorMediator mediator = mock(ContributorMediator.class); AuditTrailCollector collector = new AuditTrailCollector(settings, client, store, alarmDispatcher); - + addStep("Instantiate the service.", "Should work."); AuditTrailService service = new AuditTrailService(store, collector, mediator, settings); service.start(); - + addStep("Try to collect audit trails.", "Should make a call to the client."); CollectionRunner collectionRunner = new CollectionRunner(service); Thread t = threadFactory.newThread(collectionRunner); t.start(); - + ArgumentCaptor eventHandlerCaptor = ArgumentCaptor.forClass(EventHandler.class); verify(client, timeout(3000).times(1)).getAuditTrails(eq(TEST_COLLECTION), any(AuditTrailQuery[].class), isNull(), isNull(), eventHandlerCaptor.capture(), any(String.class)); - - AuditTrailResult event = new AuditTrailResult(DEFAULT_CONTRIBUTOR, TEST_COLLECTION, new ResultingAuditTrails(), false); + + AuditTrailResult event = new AuditTrailResult(DEFAULT_CONTRIBUTOR, TEST_COLLECTION, new ResultingAuditTrails(), + false); eventHandlerCaptor.getValue().handleEvent(event); eventHandlerCaptor.getValue().handleEvent(new CompleteEvent(TEST_COLLECTION, null)); - + addStep("Retrieve audit trails with and without an action", "Should work."); - - verify(store, times(1)).addAuditTrails(any(AuditTrailEvents.class), eq(TEST_COLLECTION), eq(DEFAULT_CONTRIBUTOR)); + + verify(store, times(1)).addAuditTrails(any(AuditTrailEvents.class), eq(TEST_COLLECTION), + eq(DEFAULT_CONTRIBUTOR)); service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, null, null, null); - verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), - isNull(), isNull(), isNull(), isNull(), - isNull(), isNull(), isNull(), isNull(), - isNull()); + verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), + isNull(), isNull(), isNull(), isNull(), isNull()); service.queryAuditTrailEventsByIterator(null, null, null, null, null, null, FileAction.FAILURE, null, null); - verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), - isNull(), isNull(), isNull(), isNull(), - eq(FileAction.FAILURE), isNull(), isNull(), isNull(), - isNull()); + verify(store, times(1)).getAuditTrailsByIterator(isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), + eq(FileAction.FAILURE), isNull(), isNull(), isNull(), isNull()); + - addStep("Shutdown", ""); service.shutdown(); } diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java index e37452d23..529926e52 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/reports/IntegrityReportProvider.java @@ -48,7 +48,8 @@ public IntegrityReportProvider(File reportsDir) { * @return IntegrityReportReader with the latest integrity report * @throws FileNotFoundException if no report could be found */ - public synchronized IntegrityReportReader getLatestIntegrityReportReader(String collectionID) throws FileNotFoundException { + public synchronized IntegrityReportReader getLatestIntegrityReportReader(String collectionID) + throws FileNotFoundException { IntegrityReportReader reader = reports.get(collectionID); if (reader == null) { log.info("Trying to lookup the latest report on disk for collection {}", collectionID); diff --git a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java index 2d7d1a07f..dab0e0f3f 100644 --- a/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java +++ b/bitrepository-integrity-service/src/main/java/org/bitrepository/integrityservice/web/RestIntegrityService.java @@ -105,29 +105,24 @@ public RestIntegrityService() { @GET @Path("/getTotalFileIDs") @Produces(MediaType.APPLICATION_JSON) - public HashMap> getTotalFileIDs( - @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("page") - int page, - @DefaultValue("100") - @QueryParam("pageSize") - int pageSize) { + public HashMap> getTotalFileIDs(@QueryParam("collectionID") String collectionID, + @QueryParam("pillarID") String pillarID, + @QueryParam("page") int page, + @DefaultValue("100") @QueryParam("pageSize") int pageSize) { IntegrityIssueIterator it = model.getFilesOnPillar(pillarID, getOffset(page, pageSize), pageSize, collectionID); if (it == null) { throw new WebApplicationException( - status(Status.NO_CONTENT).entity("Failed to get missing files from database").type(MediaType.TEXT_PLAIN).build()); + status(Status.NO_CONTENT).entity("Failed to get missing files from database") + .type(MediaType.TEXT_PLAIN).build()); } List iteratorAsList = StreamingTools.iteratorToList(it); if (iteratorAsList.isEmpty()) { throw new WebApplicationException(status(Status.NOT_FOUND).entity( - String.format(Locale.ROOT, "No fileIDs found for collection: '%s' and pillar: '%s'", collectionID, pillarID)) - .type(MediaType.TEXT_PLAIN).build()); + String.format(Locale.ROOT, "No fileIDs found for collection: '%s' and pillar: '%s'", collectionID, + pillarID)).type(MediaType.TEXT_PLAIN).build()); } return new HashMap<>(Map.of(pillarID, iteratorAsList)); @@ -142,16 +137,10 @@ public HashMap> getTotalFileIDs( @GET @Path("/getMissingFileIDs") @Produces(MediaType.APPLICATION_JSON) - public HashMap> getMissingFileIDs( - @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("page") - int page, - @DefaultValue("100") - @QueryParam("pageSize") - int pageSize) { + public HashMap> getMissingFileIDs(@QueryParam("collectionID") String collectionID, + @QueryParam("pillarID") String pillarID, + @QueryParam("page") int page, + @DefaultValue("100") @QueryParam("pageSize") int pageSize) { HashMap> output = new HashMap<>(); ReportPart part = ReportPart.MISSING_FILE; List missingOnPillar; @@ -164,9 +153,9 @@ public HashMap> getMissingFileIDs( missingOnPillar = getReportPart(part, collectionID, pillarID, page, pageSize); output.put(pillarID, missingOnPillar); } catch (FileNotFoundException e) { - throw new WebApplicationException(status(Status.NOT_FOUND).entity( - String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", - part.getHumanString(), collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException(status(Status.NOT_FOUND).entity(String.format(Locale.ROOT, + "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", part.getHumanString(), + collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); } for (String otherPillar : otherPillars) { @@ -187,17 +176,12 @@ public HashMap> getMissingFileIDs( @GET @Path("/getMissingChecksumsFileIDs") @Produces(MediaType.APPLICATION_JSON) - public HashMap> getMissingChecksums( - @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("page") - int page, - @DefaultValue("100") - @QueryParam("pageSize") - int pageSize) { - List streamingOutput = getReportPartForPillar(ReportPart.MISSING_CHECKSUM, collectionID, pillarID, page, pageSize); + public HashMap> getMissingChecksums(@QueryParam("collectionID") String collectionID, + @QueryParam("pillarID") String pillarID, + @QueryParam("page") int page, + @DefaultValue("100") @QueryParam("pageSize") int pageSize) { + List streamingOutput = getReportPartForPillar(ReportPart.MISSING_CHECKSUM, collectionID, pillarID, page, + pageSize); return new HashMap<>(Map.of(pillarID, streamingOutput)); } @@ -211,17 +195,12 @@ public HashMap> getMissingChecksums( @GET @Path("/getObsoleteChecksumsFileIDs") @Produces(MediaType.APPLICATION_JSON) - public HashMap> geObsoleteChecksums( - @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("page") - int page, - @DefaultValue("100") - @QueryParam("pageSize") - int pageSize) { - List streamingOutput = getReportPartForPillar(ReportPart.OBSOLETE_CHECKSUM, collectionID, pillarID, page, pageSize); + public HashMap> geObsoleteChecksums(@QueryParam("collectionID") String collectionID, + @QueryParam("pillarID") String pillarID, + @QueryParam("page") int page, + @DefaultValue("100") @QueryParam("pageSize") int pageSize) { + List streamingOutput = getReportPartForPillar(ReportPart.OBSOLETE_CHECKSUM, collectionID, pillarID, + page, pageSize); return new HashMap<>(Map.of(pillarID, streamingOutput)); } @@ -235,17 +214,12 @@ public HashMap> geObsoleteChecksums( @GET @Path("/getChecksumErrorFileIDs") @Produces(MediaType.APPLICATION_JSON) - public HashMap> getChecksumErrors( - @QueryParam("collectionID") - String collectionID, - @QueryParam("pillarID") - String pillarID, - @QueryParam("page") - int page, - @DefaultValue("100") - @QueryParam("pageSize") - int pageSize) { - List streamingOutput = getReportPartForPillar(ReportPart.CHECKSUM_ERROR, collectionID, pillarID, page, pageSize); + public HashMap> getChecksumErrors(@QueryParam("collectionID") String collectionID, + @QueryParam("pillarID") String pillarID, + @QueryParam("page") int page, + @DefaultValue("100") @QueryParam("pageSize") int pageSize) { + List streamingOutput = getReportPartForPillar(ReportPart.CHECKSUM_ERROR, collectionID, pillarID, page, + pageSize); return new HashMap<>(Map.of(pillarID, streamingOutput)); } @@ -255,9 +229,7 @@ public HashMap> getChecksumErrors( @GET @Path("/getIntegrityStatus") @Produces(MediaType.APPLICATION_JSON) - public String getIntegrityStatus( - @QueryParam("collectionID") - String collectionID) throws IOException { + public String getIntegrityStatus(@QueryParam("collectionID") String collectionID) throws IOException { StringWriter writer = new StringWriter(); JsonFactory jf = new JsonFactory(); JsonGenerator jg = jf.createGenerator(writer); @@ -273,17 +245,16 @@ public String getIntegrityStatus( String pillarName = Objects.requireNonNullElse(SettingsUtils.getPillarName(pillar), "N/A"); PillarType pillarTypeObject = SettingsUtils.getPillarType(pillar); String pillarType = pillarTypeObject != null ? pillarTypeObject.value() : null; - PillarCollectionStat emptyStat = new PillarCollectionStat(pillar, collectionID, pillarName, - pillarType, 0L, 0L, 0L, 0L, 0L, - 0L, "", null, new Date(0), new Date(0)); + PillarCollectionStat emptyStat = new PillarCollectionStat(pillar, collectionID, pillarName, pillarType, + 0L, 0L, 0L, 0L, 0L, 0L, "", null, new Date(0), new Date(0)); stats.put(pillar, emptyStat); } } jg.writeStartArray(); for (PillarCollectionStat stat : stats.values()) { writeIntegrityStatusObject(stat, jg); - log.debug(String.format(Locale.ROOT, "IntegrityStatus: Wrote pillar name: '%s' to pillar '%s'", stat.getPillarName(), - stat.getPillarID())); + log.debug(String.format(Locale.ROOT, "IntegrityStatus: Wrote pillar name: '%s' to pillar '%s'", + stat.getPillarName(), stat.getPillarID())); } jg.writeEndArray(); jg.flush(); @@ -297,9 +268,7 @@ public String getIntegrityStatus( @GET @Path("/getWorkflowSetup") @Produces(MediaType.APPLICATION_JSON) - public String getWorkflowSetup( - @QueryParam("collectionID") - String collectionID) throws IOException { + public String getWorkflowSetup(@QueryParam("collectionID") String collectionID) throws IOException { try { StringWriter writer = new StringWriter(); JsonFactory jf = new JsonFactory(); @@ -324,9 +293,7 @@ public String getWorkflowSetup( @GET @Path("/getWorkflowList") @Produces(MediaType.APPLICATION_JSON) - public List getWorkflowList( - @QueryParam("collectionID") - String collectionID) { + public List getWorkflowList(@QueryParam("collectionID") String collectionID) { List workflowIDs = new ArrayList<>(); for (JobID workflowID : workflowManager.getWorkflows(collectionID)) { workflowIDs.add(workflowID.getWorkflowName()); @@ -346,9 +313,7 @@ public List getWorkflowList( @GET @Path("/getAvailableIntegrityReports") @Produces(MediaType.APPLICATION_JSON) - public HashMap> getAvailableIntegrityReports( - @QueryParam("collectionID") - String collectionID) { + public HashMap> getAvailableIntegrityReports(@QueryParam("collectionID") String collectionID) { HashMap> availableIntegrityReports = new HashMap<>(); List pillars = SettingsUtils.getPillarIDsForCollection(collectionID); Set reportParts = IntegrityReportConstants.getReportParts(); @@ -375,16 +340,14 @@ public HashMap> getAvailableIntegrityReports( @GET @Path("/getLatestIntegrityReport") @Produces(MediaType.TEXT_PLAIN) - public StreamingOutput getLatestIntegrityReport( - @QueryParam("collectionID") - String collectionID) { + public StreamingOutput getLatestIntegrityReport(@QueryParam("collectionID") String collectionID) { final File fullReport; try { fullReport = integrityReportProvider.getLatestIntegrityReportReader(collectionID).getFullReport(); } catch (FileNotFoundException e) { throw new WebApplicationException(status(Status.NOT_FOUND).entity( - String.format(Locale.ROOT, "No integrity report for collection: '%s' found!", collectionID)).type(MediaType.TEXT_PLAIN) - .build()); + String.format(Locale.ROOT, "No integrity report for collection: '%s' found!", collectionID)) + .type(MediaType.TEXT_PLAIN).build()); } return output -> streamFile(fullReport, output); } @@ -392,11 +355,8 @@ public StreamingOutput getLatestIntegrityReport( @GET @Path("/getIntegrityReportsAsZIP") @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response getIntegrityReportsAsZIP( - @QueryParam("collectionID") - String collectionID, - @QueryParam("reports") - List reports) { + public Response getIntegrityReportsAsZIP(@QueryParam("collectionID") String collectionID, + @QueryParam("reports") List reports) { String fileName = "IntegrityReports.zip"; HashMap files = new HashMap<>(); @@ -417,9 +377,9 @@ public Response getIntegrityReportsAsZIP( zipOut.write(Files.readAllBytes(value.toPath())); zipOut.flush(); } catch (IOException e) { - throw new WebApplicationException( - status(Status.INTERNAL_SERVER_ERROR).entity("Something went wrong when trying to zip the file " + key + ".") - .type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException(status(Status.INTERNAL_SERVER_ERROR).entity( + "Something went wrong when trying to zip the file " + key + ".").type(MediaType.TEXT_PLAIN) + .build()); } }); zipOut.close(); @@ -445,10 +405,12 @@ public File getLatestIntegrityReportPartFile(String collectionID, String reportP try { reportPartFile = integrityReportProvider.getIntegrityReportPart(collectionID, pillarID, reportPart); } catch (FileNotFoundException e) { - String errorMessage = String.format(Locale.ROOT, "No '%s' report part for collection: '%s' and pillar: '%s' found!", reportPart, - collectionID, pillarID); + String errorMessage = String.format(Locale.ROOT, + "No '%s' report part for collection: '%s' and pillar: '%s' found!", reportPart, collectionID, + pillarID); log.error(errorMessage); - throw new WebApplicationException(status(Status.NOT_FOUND).entity(errorMessage).type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException( + status(Status.NOT_FOUND).entity(errorMessage).type(MediaType.TEXT_PLAIN).build()); } return reportPartFile; } @@ -460,11 +422,8 @@ public File getLatestIntegrityReportPartFile(String collectionID, String reportP @Path("/startWorkflow") @Consumes("application/x-www-form-urlencoded") @Produces("text/html") - public String startWorkflow( - @FormParam("workflowID") - String workflowID, - @FormParam("collectionID") - String collectionID) { + public String startWorkflow(@FormParam("workflowID") String workflowID, + @FormParam("collectionID") String collectionID) { log.debug("Starting workflow '" + workflowID + "' on collection '" + collectionID + "'."); return workflowManager.startWorkflow(new JobID(workflowID, collectionID)); } @@ -475,9 +434,7 @@ public String startWorkflow( @GET @Path("/getCollectionInformation") @Produces(MediaType.APPLICATION_JSON) - public String getCollectionInformation( - @QueryParam("collectionID") - String collectionID) throws IOException { + public String getCollectionInformation(@QueryParam("collectionID") String collectionID) throws IOException { StringWriter writer = new StringWriter(); JsonFactory jf = new JsonFactory(); JsonGenerator jg = jf.createGenerator(writer); @@ -531,14 +488,18 @@ private List getReportPart(ReportPart part, String collectionID, String * * @return Returns either a {@link List} of fileIDs or throws a {@link WebApplicationException}. */ - private List getReportPartForPillar(ReportPart part, String collectionID, String pillarID, int page, int pageSize) { + private List getReportPartForPillar(ReportPart part, + String collectionID, + String pillarID, + int page, + int pageSize) { List reportPartContent; try { reportPartContent = getReportPart(part, collectionID, pillarID, page, pageSize); } catch (FileNotFoundException e) { - throw new WebApplicationException(status(Status.NOT_FOUND).entity( - String.format(Locale.ROOT, "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", - part.getHumanString(), collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); + throw new WebApplicationException(status(Status.NOT_FOUND).entity(String.format(Locale.ROOT, + "No integrity '%s' report part for collection: '%s' and pillar: '%s' found!", part.getHumanString(), + collectionID, pillarID)).type(MediaType.TEXT_PLAIN).build()); } return reportPartContent; } @@ -556,7 +517,10 @@ private List getReportPartForPillar(ReportPart part, String collectionID * @param pageSize The paging size. * @return Returns a {@link List} containing the files that were also missing on the given pillar. */ - private List compareMissingFiles(List missingOnPillar, String collectionID, String pillar, int pageSize) { + private List compareMissingFiles(List missingOnPillar, + String collectionID, + String pillar, + int pageSize) { List batchToCheck; List agreedMissingFileIDs = new ArrayList<>(); for (String missingFileID : missingOnPillar) { diff --git a/bitrepository-reference-pillar/src/main/java/org/bitrepository/pillar/Pillar.java b/bitrepository-reference-pillar/src/main/java/org/bitrepository/pillar/Pillar.java index 9734045ad..a77ef963d 100644 --- a/bitrepository-reference-pillar/src/main/java/org/bitrepository/pillar/Pillar.java +++ b/bitrepository-reference-pillar/src/main/java/org/bitrepository/pillar/Pillar.java @@ -90,8 +90,8 @@ public Pillar(MessageBus messageBus, Settings settings, StorageModel pillarModel */ private void initializeWorkflows() { Long interval = DEFAULT_RECALCULATION_WORKFLOW_TIME; - Duration recalculateOldChecksumsInterval = - settings.getReferenceSettings().getPillarSettings().getRecalculateOldChecksumsInterval(); + Duration recalculateOldChecksumsInterval = settings.getReferenceSettings().getPillarSettings() + .getRecalculateOldChecksumsInterval(); if (recalculateOldChecksumsInterval != null) { interval = XmlUtils.xmlDurationToMilliseconds(recalculateOldChecksumsInterval); }