Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public void init() throws IOException {
verifier.setHttpClient(httpClient);
verifier.setProject(project);
verifier.setShowProgress(true);
verifier.setChompbConfig(parentCommand.getChompbConfig());
}

@Override
Expand All @@ -47,7 +48,8 @@ public Integer call() throws Exception {
outputLogger.info("Checked {} out of {} objects in the report",
outcome.verifiedCount, outcome.totalRecords);
if (outcome.hasErrors()) {
outputLogger.info("Errors encountered for {} objects, see report for details:", outcome.errorCount);
outputLogger.info("Boxc URL Errors encountered for {} objects, see report for details:", outcome.urlErrorCount);
outputLogger.info("Parent Collection Errors encountered for {} objects:", outcome.parentCollErrorCount);
outputLogger.info(project.getPostMigrationReportPath().toString());
return 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void addWorkRow(String cdmObjectId, String boxcWorkId, int childCount, bo
}

addRow(cdmObjectId, cdmUrl, objType, boxcUrl, boxcTitle, matchingValue, sourceFile,
null, parentUrl, parentTitle, childCount);
null, parentUrl, parentTitle, childCount, null, null);
}

/**
Expand Down Expand Up @@ -165,14 +165,14 @@ public void addFileRow(String fileCdmId, String parentCdmId, String boxcWorkId,
}

addRow(fileCdmId, cdmUrl, objType, boxcUrl, boxcTitle, matchingValue, sourceFile,
null, parentUrl, parentTitle, null);
null, parentUrl, parentTitle, null, null, null);
}

protected void addRow(String cdmId, String cdmUrl, String objType, String boxcUrl, String boxcTitle,
String matchingValue, String sourceFile, String verified, String parentUrl,
String parentTitle, Integer childCount) throws IOException {
String parentTitle, Integer childCount, String parentCollUrl, String parentCollTitle) throws IOException {
csvPrinter.printRecord(cdmId, cdmUrl, objType, boxcUrl, boxcTitle, matchingValue, sourceFile,
verified, parentUrl, parentTitle, childCount);
verified, parentUrl, parentTitle, childCount, parentCollUrl, parentCollTitle);
}

private String buildCdmUrl(String cdmObjectId, boolean isWorkObject, boolean isSingleItem) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
package edu.unc.lib.boxc.migration.cdm.services;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.unc.lib.boxc.migration.cdm.exceptions.InvalidProjectStateException;
import edu.unc.lib.boxc.migration.cdm.model.MigrationProject;
import edu.unc.lib.boxc.migration.cdm.util.DisplayProgressUtil;
import edu.unc.lib.boxc.migration.cdm.util.PostMigrationReportConstants;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.springframework.http.HttpStatus;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;

import static edu.unc.lib.boxc.migration.cdm.util.PostMigrationReportConstants.API_PATH;
import static edu.unc.lib.boxc.migration.cdm.util.PostMigrationReportConstants.RECORD_PATH;
import static org.slf4j.LoggerFactory.getLogger;

/**
* Service which verifies the Box-c URLs in the post migration report and updates the verified field
*
* @author bbpennel
*/
public class PostMigrationReportVerifier {
private static final Logger log = getLogger(PostMigrationReportVerifier.class);
private MigrationProject project;
private CloseableHttpClient httpClient;
private ChompbConfigService.ChompbConfig chompbConfig;
private boolean showProgress;

public VerificationOutcome verify() throws IOException {
public VerificationOutcome verify() throws IOException, URISyntaxException {
validateReport();

var outcome = new VerificationOutcome();
Expand All @@ -42,20 +55,30 @@ public VerificationOutcome verify() throws IOException {
) {
long currentNum = 0;
updateProgressDisplay(currentNum, totalRecords);
var baseUrl = chompbConfig.getBxcEnvironments().get(project.getProjectProperties().getBxcEnvironmentId()).getHttpBaseUrl();

for (CSVRecord originalRecord : csvParser) {
var verified = originalRecord.get(PostMigrationReportConstants.VERIFIED_HEADER);

var rowValues = originalRecord.toList();
var rowValuesMap = originalRecord.toMap();
var boxcUrl = originalRecord.get(PostMigrationReportConstants.BXC_URL_HEADER);
// 'verified' field is empty or was not previously successful, so request the boxc url
if (!isStatusAcceptable(verified)) {
var boxcUrl = originalRecord.get(PostMigrationReportConstants.BXC_URL_HEADER);
var result = requestHttpResult(boxcUrl);
outcome.recordResult(result);
rowValues.set(PostMigrationReportConstants.VERIFIED_INDEX, result);
rowValuesMap.put(PostMigrationReportConstants.VERIFIED_HEADER, result);
}

// add parent collection information
var parentCollInfo = getParentCollectionInfo(boxcUrl, outcome, baseUrl + API_PATH);
var parentCollId = parentCollInfo.get("id");
rowValuesMap.put(PostMigrationReportConstants.PARENT_COLL_URL_HEADER,
formatParentCollUrl(parentCollId, baseUrl + RECORD_PATH));
rowValuesMap.put(PostMigrationReportConstants.PARENT_COLL_TITLE_HEADER, parentCollInfo.get("name"));


// Write the row out into the new version of the report
csvPrinter.printRecord(rowValues);
csvPrinter.printRecord(rowValuesMap.values());

currentNum++;
updateProgressDisplay(currentNum, totalRecords);
Expand Down Expand Up @@ -92,6 +115,41 @@ private String requestHttpResult(String bxcUrl) throws IOException {
}
}

private Map<String, String> getParentCollectionInfo(String bxcUrl, VerificationOutcome outcome, String bxcApiBaseUrl) throws IOException, URISyntaxException {
var map = new HashMap<String, String>();
var id = getId(bxcUrl);
var getRequest = new HttpGet(URI.create(bxcApiBaseUrl + id+ "/json"));
try (var resp = httpClient.execute(getRequest)) {
if (resp.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
map.put("id", "");
map.put("name", "");
outcome.recordParentCollError();
return map;
}
var body = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
var mapper = new ObjectMapper();
var jsonNode = mapper.readTree(body);
map.put("id", jsonNode.get("briefObject").get("parentCollectionId").asText());
map.put("name", jsonNode.get("briefObject").get("parentCollectionName").asText());
}
return map;
}

private String getId(String url) throws URISyntaxException {
var uri = new URI(url);
String path = uri.getPath();

String[] parts = path.split("/");
return parts[parts.length - 1];
}

private String formatParentCollUrl(String id, String bxcRecordBaseUrl) {
if (id.isBlank()) {
return "";
}
return bxcRecordBaseUrl + id;
}

private CSVParser openCsvParser() throws IOException {
Reader reader = Files.newBufferedReader(project.getPostMigrationReportPath());
return new CSVParser(reader, PostMigrationReportConstants.CSV_PARSER_FORMAT);
Expand Down Expand Up @@ -135,24 +193,33 @@ public void setShowProgress(boolean showProgress) {
this.showProgress = showProgress;
}

public void setChompbConfig(ChompbConfigService.ChompbConfig chompbConfig) {
this.chompbConfig = chompbConfig;
}

private static boolean isStatusAcceptable(String status) {
return HttpStatus.OK.name().equals(status) || HttpStatus.FORBIDDEN.name().equals(status);
}

public static class VerificationOutcome {
public long errorCount = 0;
public long urlErrorCount = 0;
public long verifiedCount = 0;
public long totalRecords = 0;
public long parentCollErrorCount = 0;

protected void recordResult(String result) {
if (!isStatusAcceptable(result)) {
errorCount++;
urlErrorCount++;
}
verifiedCount++;
}

protected void recordParentCollError() {
parentCollErrorCount++;
}

public boolean hasErrors() {
return errorCount > 0;
return urlErrorCount > 0 || parentCollErrorCount > 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@
public class PostMigrationReportConstants {
public static final String BXC_URL_HEADER = "boxc_url";
public static final String VERIFIED_HEADER = "verified";
public static final int VERIFIED_INDEX = 7;
public static final String PARENT_COLL_URL_HEADER = "parent_collection_url";
public static final String PARENT_COLL_TITLE_HEADER = "parent_collection_title";
public static final String RECORD_PATH = "record/";
public static final String API_PATH = "api/" + RECORD_PATH;

public static final String[] CSV_HEADERS = new String[] {
"cdm_id", "cdm_url", "boxc_obj_type", "boxc_url", "boxc_title", "matching_value", "source_file",
VERIFIED_HEADER, "boxc_parent_work_url", "boxc_parent_work_title", "children_count" };
VERIFIED_HEADER, "boxc_parent_work_url", "boxc_parent_work_title", "children_count", PARENT_COLL_URL_HEADER,
PARENT_COLL_TITLE_HEADER };
public static final CSVFormat CSV_OUTPUT_FORMAT = CSVFormat.Builder.create()
.setHeader(CSV_HEADERS)
.build();
.get();
public static final CSVFormat CSV_PARSER_FORMAT = CSVFormat.Builder.create()
.setSkipHeaderRecord(true)
.setHeader(CSV_HEADERS)
.setTrim(true)
.build();
.get();

private PostMigrationReportConstants() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
import static edu.unc.lib.boxc.migration.cdm.test.PostMigrationReportTestHelper.JSON;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
Expand Down Expand Up @@ -54,6 +57,10 @@ public void successTest() throws Exception {
stubFor(get(urlMatching("/bxc/record/.*"))
.willReturn(aResponse()
.withStatus(HttpStatus.OK.value())));
stubFor(get(urlMatching("/bxc/api/.*"))
.willReturn(aResponse()
.withBody(JSON)
.withStatus(HttpStatus.OK.value())));

generateSip();

Expand All @@ -72,6 +79,10 @@ public void errorsTest() throws Exception {
stubFor(get(urlMatching("/bxc/record/.*"))
.willReturn(aResponse()
.withStatus(HttpStatus.NOT_FOUND.value())));
stubFor(get(urlMatching("/bxc/api/.*"))
.willReturn(aResponse()
.withBody(JSON)
.withStatus(HttpStatus.OK.value())));

generateSip();

Expand All @@ -84,6 +95,26 @@ public void errorsTest() throws Exception {
assertTrue(Files.readString(project.getPostMigrationReportPath()).contains(HttpStatus.NOT_FOUND.name()));
}

@Test
public void parentCollectionErrorsTest() {
stubFor(get(urlMatching("/bxc/record/.*"))
.willReturn(aResponse()
.withStatus(HttpStatus.OK.value())));
stubFor(get(urlMatching("/bxc/api/.*"))
.willReturn(aResponse()
.withBody(JSON)
.withStatus(HttpStatus.NOT_FOUND.value())));

generateSip();

String[] args = new String[] {
"-w", project.getProjectPath().toString(),
"verify_migration" };
executeExpectFailure(args);
assertOutputContains("Parent Collection Errors encountered for 6 objects");
assertTrue(Files.exists(project.getPostMigrationReportPath()));
}

private void generateSip() {
var sipService = testHelper.createSipsService();
var sipOptions = new SipGenerationOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ public void setup() throws Exception {
public void reportCountWorksTest() throws Exception {
reportGenerator.init();
reportGenerator.addRow("25", CDM_URL_1, "Work", BOXC_URL_1, "Redoubt C",
null, null, null, "", "", 1);
null, null, null, "", "", 1, null, null);
reportGenerator.addRow("26", CDM_URL_2, "File", BOXC_URL_2, "A file",
null, null, null, BOXC_URL_1, "Redoubt C", null);
null, null, null, BOXC_URL_1, "Redoubt C", null, null, null);
reportGenerator.closeCsv();

long numWorks = service.countWorks();
Expand All @@ -64,11 +64,11 @@ public void reportCountWorksTest() throws Exception {
public void reportCountFilesTest() throws Exception {
reportGenerator.init();
reportGenerator.addRow("25", CDM_URL_1, "Work", BOXC_URL_1, "Redoubt C",
null, null, null, "", "", 1);
null, null, null, "", "", 1, null, null);
reportGenerator.addRow("26", CDM_URL_2, "File", BOXC_URL_2, "A file",
null, null, null, BOXC_URL_1, "Redoubt C", null);
null, null, null, BOXC_URL_1, "Redoubt C", null, null, null);
reportGenerator.addRow("27", CDM_URL_3, "File", BOXC_URL_3, "A file",
null, null, null, BOXC_URL_1, "Redoubt C", null);
null, null, null, BOXC_URL_1, "Redoubt C", null, null, null);
reportGenerator.closeCsv();

long numFiles = service.countFiles();
Expand Down
Loading