Skip to content

Commit 5067b42

Browse files
authored
BXC-4802 updating tests and code for zero byte JP2s (#1864)
* BXC-4802 updating tests and code for zero byte JP2s * BXC-4802 fix test * BXC-4802 adjusting manifest logic for differences in listViewableFiles for canvases and manifests * BXC-4802 update exception message * BXC-4802 trying to fix tests * BXC-4802 DRY up method * BXC-4802 fix tests and remove unneeded method * BXC-4802 fix tests * BXC-4802 fix last test * BXC-4802 add test for manifest service * BXC-4802 add new test for canvas for non viewable files * BXC-4802 accounting for filsize of 0 * BXC-4802 remove extent check * BXC-4802 account for no filesize in jp2 datastreams * BXC-4802 update invalid jp2 logic * BXC-4802 update corpus and solr test
1 parent 1195ee5 commit 5067b42

File tree

9 files changed

+263
-59
lines changed

9 files changed

+263
-59
lines changed

indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/action/DeleteSolrTreeTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public void deleteTree() throws Exception {
9494
server.commit();
9595

9696
SolrDocumentList docListAfter = getDocumentList();
97-
assertEquals(2, docListAfter.getNumFound());
97+
assertEquals(4, docListAfter.getNumFound());
9898

9999
assertObjectsNotExist(corpus.pid2, corpus.pid4, corpus.pid6, corpus.pid5);
100100
}
@@ -108,7 +108,7 @@ public void deleteNonexistent() throws Exception {
108108

109109
SolrDocumentList docListAfter = getDocumentList();
110110

111-
assertEquals(7, docListAfter.getNumFound());
111+
assertEquals(9, docListAfter.getNumFound());
112112
}
113113

114114
@Test
@@ -119,7 +119,7 @@ public void deleteSimple() throws Exception {
119119
server.commit();
120120

121121
SolrDocumentList docListAfter = getDocumentList();
122-
assertEquals(5, docListAfter.getNumFound(), "One object should have been removed");
122+
assertEquals(7, docListAfter.getNumFound(), "One object should have been removed");
123123

124124
assertObjectsNotExist(corpus.pid6);
125125
}

indexing-solr/src/test/java/edu/unc/lib/boxc/indexing/solr/test/TestCorpus.java

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* > obj4
2929
* > obj5
3030
* > obj6
31+
* > obj7
3132
* > obj3
3233
*
3334
* @author bbpennel
@@ -40,7 +41,9 @@ public class TestCorpus {
4041
public PID pid4;
4142
public PID pid5;
4243
public PID pid6;
44+
public PID pid7;
4345
public PID pid6File;
46+
public PID pid7File;
4447
public PID nonExistentPid;
4548

4649
public TestCorpus() {
@@ -50,7 +53,9 @@ public TestCorpus() {
5053
pid4 = makePid();
5154
pid5 = makePid();
5255
pid6 = makePid();
56+
pid7 = makePid();
5357
pid6File = makePid();
58+
pid7File = makePid();
5459
nonExistentPid = makePid();
5560
}
5661

@@ -79,7 +84,7 @@ public List<SolrInputDocument> populate() {
7984
newDoc.addField("ancestorPath", makeAncestorPath(pid1));
8085
newDoc.addField("resourceType", "Collection");
8186
List<String> collectionDatastream = List.of(
82-
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|||" + pid2.getId() + "|1200x1200");
87+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|766||" + pid2.getId() + "|1200x1200");
8388
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), collectionDatastream);
8489
docs.add(newDoc);
8590

@@ -119,7 +124,7 @@ public List<SolrInputDocument> populate() {
119124
newDoc.addField("resourceType", ResourceType.File.name());
120125
List<String> imgDatastreams = Arrays.asList(
121126
ORIGINAL_FILE.getId() + "|image/png|file.png|png|766|urn:sha1:checksum||1200x1200",
122-
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|||" + pid6File.getId() + "|1200x1200");
127+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|766||" + pid6File.getId() + "|1200x1200");
123128
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), imgDatastreams);
124129
newDoc.addField(SearchFieldKey.FILE_FORMAT_CATEGORY.getSolrField(), ContentCategory.image.getDisplayName());
125130
newDoc.addField(SearchFieldKey.FILE_FORMAT_TYPE.getSolrField(), "png");
@@ -137,12 +142,48 @@ public List<SolrInputDocument> populate() {
137142
newDoc.addField("resourceType", ResourceType.Work.name());
138143
List<String> workDatastreams = Arrays.asList(
139144
ORIGINAL_FILE.getId() + "|image/png|file.png|png|766|urn:sha1:checksum|" + pid6File.getId() + "|1200x1200",
140-
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|||" + pid6File.getId() + "|1200x1200");
145+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|766||" + pid6File.getId() + "|1200x1200");
141146
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), workDatastreams);
142147
newDoc.addField(SearchFieldKey.FILE_FORMAT_CATEGORY.getSolrField(), ContentCategory.image.getDisplayName());
143148
newDoc.addField(SearchFieldKey.FILE_FORMAT_TYPE.getSolrField(), "png");
144149
docs.add(newDoc);
145150

151+
newDoc = new SolrInputDocument();
152+
newDoc.addField("title", "Work2");
153+
newDoc.addField("id", pid7.getId());
154+
newDoc.addField("rollup", pid7.getId());
155+
newDoc.addField("roleGroup", "public admin");
156+
newDoc.addField("readGroup", "public");
157+
newDoc.addField("adminGroup", "admin");
158+
newDoc.addField("ancestorIds", makeAncestorIds(pid1, pid3));
159+
newDoc.addField("ancestorPath", makeAncestorPath(pid1, pid3));
160+
newDoc.addField("resourceType", ResourceType.Work.name());
161+
List<String> work2Datastreams = Arrays.asList(
162+
ORIGINAL_FILE.getId() + "|image/png|file.png|png|766|urn:sha1:checksum|" + pid6File.getId() + "|1200x1200",
163+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|766||" + pid6File.getId() + "|1200x1200");
164+
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), work2Datastreams);
165+
newDoc.addField(SearchFieldKey.FILE_FORMAT_CATEGORY.getSolrField(), ContentCategory.image.getDisplayName());
166+
newDoc.addField(SearchFieldKey.FILE_FORMAT_TYPE.getSolrField(), "png");
167+
docs.add(newDoc);
168+
169+
newDoc = new SolrInputDocument();
170+
newDoc.addField("title", "File2");
171+
newDoc.addField("id", pid7File.getId());
172+
newDoc.addField("rollup", pid7.getId());
173+
newDoc.addField("roleGroup", "public admin");
174+
newDoc.addField("readGroup", "public");
175+
newDoc.addField("adminGroup", "admin");
176+
newDoc.addField("ancestorIds", makeAncestorIds(pid1, pid3, pid7));
177+
newDoc.addField("ancestorPath", makeAncestorPath(pid1, pid3, pid7));
178+
newDoc.addField("resourceType", ResourceType.File.name());
179+
List<String> fileDatastreams = Arrays.asList(
180+
ORIGINAL_FILE.getId() + "|image/png|file.png|png|766|urn:sha1:checksum||120x120",
181+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|766||" + pid7File.getId() + "|120x120");
182+
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), fileDatastreams);
183+
newDoc.addField(SearchFieldKey.FILE_FORMAT_CATEGORY.getSolrField(), ContentCategory.image.getDisplayName());
184+
newDoc.addField(SearchFieldKey.FILE_FORMAT_TYPE.getSolrField(), "png");
185+
docs.add(newDoc);
186+
146187
newDoc = new SolrInputDocument();
147188
newDoc.addField("title", "Second collection");
148189
newDoc.addField("id", pid3.getId());
@@ -154,7 +195,7 @@ public List<SolrInputDocument> populate() {
154195
newDoc.addField("ancestorPath", makeAncestorPath(pid1));
155196
newDoc.addField("resourceType", "Collection");
156197
List<String> collection2Datastream = List.of(
157-
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|||" + pid2.getId() + "|120x120");
198+
DatastreamType.JP2_ACCESS_COPY.getId() + "|image/jp2|bunny.jp2|jp2|0||" + pid2.getId() + "|1200x1200");
158199
newDoc.addField(SearchFieldKey.DATASTREAM.getSolrField(), collection2Datastream);
159200
docs.add(newDoc);
160201

web-services-app/src/main/java/edu/unc/lib/boxc/web/services/processing/DownloadImageService.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ public class DownloadImageService {
4343
*/
4444
public ResponseEntity<InputStreamResource> streamImage(ContentObjectRecord contentObjectRecord, String size, boolean attachment)
4545
throws IOException {
46-
if (contentObjectRecord.getDatastreamObject(DatastreamType.JP2_ACCESS_COPY.getId()) == null) {
47-
return ResponseEntity.notFound().build();
48-
}
49-
5046
var contentDispositionHeader = "inline;";
5147
if (attachment) {
5248
String filename = getDownloadFilename(contentObjectRecord, size);
@@ -82,6 +78,9 @@ public String getSize(ContentObjectRecord contentObjectRecord, String size) {
8278
if (!Objects.equals(size, FULL_SIZE)) {
8379
int integerSize = parseSize(size);
8480
var longerSide = getLongestSide(contentObjectRecord);
81+
if (longerSide == 0) {
82+
return null;
83+
}
8584
// request is bigger than or equal to full size, so we will switch to full size
8685
if (integerSize >= longerSide) {
8786
return FULL_SIZE;
@@ -144,7 +143,8 @@ private String getExtent(ContentObjectRecord contentObjectRecord) {
144143
}
145144

146145
/**
147-
* If the shortest side of the content object is smaller than the size requested, return the placeholder
146+
* If the shortest side of the content object is smaller than the size requested or if there is no
147+
* valid JP2, then return the placeholder
148148
* @param contentObjectRecord
149149
* @param size
150150
* @return true if service needs to return a placeholder image
@@ -153,6 +153,9 @@ private boolean needsPlaceholder(ContentObjectRecord contentObjectRecord, String
153153
if (Objects.equals(FULL_SIZE, size)) {
154154
return false;
155155
}
156+
if (isInvalidJP2Datastream(contentObjectRecord)) {
157+
return true;
158+
}
156159
var shortestSide = getShortestSide(contentObjectRecord);
157160
return shortestSide < Integer.parseInt(size);
158161
}
@@ -190,6 +193,11 @@ private String getPlaceholderUrl(String size) {
190193
return iiifBasePath + PLACEHOLDER_ID + "/full/" + formattedSize + "/0/default.png";
191194
}
192195

196+
public boolean isInvalidJP2Datastream(ContentObjectRecord contentObjectRecord) {
197+
var datastream = contentObjectRecord.getDatastreamObject(DatastreamType.JP2_ACCESS_COPY.getId());
198+
return datastream == null || datastream.getFilesize() == 0;
199+
}
200+
193201
public void setIiifBasePath(String iiifBasePath) {
194202
this.iiifBasePath = iiifBasePath;
195203
}

web-services-app/src/main/java/edu/unc/lib/boxc/web/services/processing/IiifV3ManifestService.java

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,13 @@ public class IiifV3ManifestService {
8080
*/
8181
public Manifest buildManifest(PID pid, AgentPrincipals agent) {
8282
assertHasAccess(pid, agent);
83-
var contentObjs = listViewableFiles(pid, agent.getPrincipals());
84-
if (contentObjs.isEmpty()) {
83+
ContentObjectRecord rootObj = solrSearchService.getObjectById(new SimpleIdRequest(pid, agent.getPrincipals()));
84+
if (rootObj == null) {
8585
throw new NotFoundException("No objects were found for inclusion in manifest for object " + pid.getId());
8686
}
87+
var contentObjs = listViewableFiles(rootObj, agent.getPrincipals());
8788
log.debug("Constructing manifest for {} containing {} items", pid.getId(), contentObjs.size());
88-
ContentObjectRecord rootObj = contentObjs.get(0);
89+
8990
var manifest = new Manifest(getManifestPath(rootObj), new Label(getTitle(rootObj)));
9091
manifest.setMetadata(constructMetadataSection(rootObj));
9192
addAttribution(manifest, rootObj);
@@ -155,9 +156,12 @@ private void addCanvasItems(Manifest manifest, List<ContentObjectRecord> content
155156
*/
156157
public Canvas buildCanvas(PID pid, AgentPrincipals agent) {
157158
assertHasAccess(pid, agent);
158-
var contentObjs = listViewableFiles(pid, agent.getPrincipals());
159-
ContentObjectRecord rootObj = contentObjs.get(0);
160-
return constructCanvasSection(rootObj);
159+
ContentObjectRecord obj = solrSearchService.getObjectById(new SimpleIdRequest(pid, agent.getPrincipals()));
160+
if (obj == null || !hasViewableContent(obj)) {
161+
throw new NotFoundException("No objects were found for canvas for object " + pid.getId());
162+
}
163+
164+
return constructCanvasSection(obj);
161165
}
162166

163167
/**
@@ -319,9 +323,9 @@ private boolean hasViewableContent(ContentObjectRecord contentObj) {
319323
}
320324

321325
var jp2Datastream = contentObj.getDatastreamObject(DatastreamType.JP2_ACCESS_COPY.getId());
322-
var isValidDatastream = jp2Datastream != null;
326+
var isValidDatastream = jp2Datastream != null && jp2Datastream.getFilesize() != 0;
323327
var originalDatastream = contentObj.getDatastreamObject(DatastreamType.ORIGINAL_FILE.getId());
324-
// check if original datastream mimetype is image or video
328+
// check if original datastream mimetype is audio or video
325329
if (!isValidDatastream && originalDatastream != null) {
326330
var mimetype = originalDatastream.getMimetype();
327331
isValidDatastream = isAudio(mimetype, contentObj) || isVideo(mimetype);
@@ -331,27 +335,21 @@ private boolean hasViewableContent(ContentObjectRecord contentObj) {
331335
}
332336

333337
/**
334-
* List viewable files for the specified object
335-
* @param pid
338+
* List viewable files for the specified object's manifest
339+
* @param rootObj
336340
* @param principals
337341
* @return
338342
*/
339-
private List<ContentObjectRecord> listViewableFiles(PID pid, AccessGroupSet principals) {
340-
ContentObjectRecord briefObj = solrSearchService.getObjectById(new SimpleIdRequest(pid, principals));
341-
if (briefObj == null) {
342-
return Collections.emptyList();
343-
}
344-
String resourceType = briefObj.getResourceType();
345-
if (hasViewableContent(briefObj)) {
346-
return Collections.singletonList(briefObj);
343+
private List<ContentObjectRecord> listViewableFiles(ContentObjectRecord rootObj, AccessGroupSet principals) {
344+
String resourceType = rootObj.getResourceType();
345+
if (hasViewableContent(rootObj)) {
346+
return Collections.singletonList(rootObj);
347347
}
348348
if (!ResourceType.Work.nameEquals(resourceType)) {
349349
return Collections.emptyList();
350350
}
351351

352-
var mdObjs = performQuery(briefObj, principals);
353-
mdObjs.add(0, briefObj);
354-
return mdObjs;
352+
return performQuery(rootObj, principals);
355353
}
356354

357355
private List<ContentObjectRecord> performQuery(ContentObjectRecord briefObj, AccessGroupSet principals) {

web-services-app/src/main/java/edu/unc/lib/boxc/web/services/rest/DownloadImageController.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,17 @@ public ResponseEntity<InputStreamResource> getImage(@PathVariable("pid") String
5858
log.error("No content object found for {}", pidString);
5959
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
6060
}
61+
62+
if (downloadImageService.isInvalidJP2Datastream(contentObjectRecord)) {
63+
log.error("No valid JP2 datastream for {}", pidString);
64+
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
65+
}
66+
6167
String validatedSize = downloadImageService.getSize(contentObjectRecord, size);
68+
if (validatedSize == null) {
69+
log.error("No validated size found for {}", pidString);
70+
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
71+
}
6272

6373
if (Objects.equals(validatedSize, ImageServerUtil.FULL_SIZE)) {
6474
aclService.assertHasAccess("Insufficient permissions to download full size copy for " + pidString,

0 commit comments

Comments
 (0)