From 668965d7efb1fd6fab262fd28007b8a0ee8e6b01 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Thu, 29 Aug 2024 23:40:50 -0400 Subject: [PATCH 1/8] WIP --- .../iiif/presentation/v3/AbstractCanvas.java | 27 +++--- .../v3/AbstractContentResource.java | 2 - .../presentation/v3/AbstractResource.java | 23 ++--- .../presentation/v3/AnnotationCollection.java | 4 +- .../iiif/presentation/v3/Canvas.java | 12 +-- .../iiif/presentation/v3/CanvasResource.java | 6 +- .../iiif/presentation/v3/Collection.java | 92 ++++++++++++++++--- .../iiif/presentation/v3/Manifest.java | 88 +++++++----------- .../presentation/v3/NavigableResource.java | 9 +- .../iiif/presentation/v3/Range.java | 4 +- .../iiif/presentation/v3/RangeCanvas.java | 16 ++-- .../iiif/presentation/v3/Resource.java | 13 +-- .../iiif/presentation/v3/TextualBody.java | 16 ++-- .../presentation/v3/AbstractCanvasTest.java | 12 +-- .../v3/AccompanyingCanvasTest.java | 6 +- .../v3/AnnotationCollectionTest.java | 3 +- .../iiif/presentation/v3/CanvasTest.java | 8 +- .../iiif/presentation/v3/CollectionTest.java | 18 ++-- .../presentation/v3/ImageContentTest.java | 4 +- .../iiif/presentation/v3/ManifestTest.java | 13 ++- .../v3/PlaceholderCanvasTest.java | 3 +- .../iiif/presentation/v3/RangeTest.java | 5 +- .../iiif/presentation/v3/TextualBodyTest.java | 8 +- .../v3/examples/CookbooksTest.java | 34 +++---- .../v3/ids/DefaultMinterTest.java | 2 +- .../v3/ids/SkolemIriFactoryTest.java | 7 +- 26 files changed, 247 insertions(+), 188 deletions(-) diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java index b9b9a00f..c54171ca 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java @@ -75,7 +75,7 @@ abstract class AbstractCanvas> extends NavigableReso private Minter myMinter; /** The canvas' other canvases (other than painting or supplementing). */ - private List> myOtherAnnotations; + private List> myWebAnnotations; /** The painting annotations on the canvas. */ private List> myPaintingPageList; @@ -149,8 +149,7 @@ public boolean equals(final Object aObject) { other = (AbstractCanvas) aObject; return Objects.equals(myDuration, other.myDuration) && Objects.equals(myHeight, other.myHeight) && - Objects.equals(myWidth, other.myWidth) && - Objects.equals(myOtherAnnotations, other.myOtherAnnotations) && + Objects.equals(myWidth, other.myWidth) && Objects.equals(myWebAnnotations, other.myWebAnnotations) && Objects.equals(myPaintingPageList, other.myPaintingPageList) && Objects.equals(mySupplementingPageList, other.mySupplementingPageList) && super.equals(other); } @@ -193,12 +192,12 @@ public Optional getMinter() { * @return The canvas' non-painting annotation pages */ @JsonIgnore - public List> getOtherAnnotations() { - if (myOtherAnnotations == null) { - myOtherAnnotations = new ArrayList<>(); + public List> getWebAnnotations() { + if (myWebAnnotations == null) { + myWebAnnotations = new ArrayList<>(); } - return myOtherAnnotations; + return myWebAnnotations; } /** @@ -243,7 +242,7 @@ public int getWidth() { @Override public int hashCode() { - return Objects.hash(super.hashCode(), myDuration, myHeight, myWidth, myOtherAnnotations, myPaintingPageList, + return Objects.hash(super.hashCode(), myDuration, myHeight, myWidth, myWebAnnotations, myPaintingPageList, mySupplementingPageList); } @@ -317,8 +316,8 @@ public T setMinter(final Minter aMinter) { */ @JsonIgnore @SafeVarargs - public final T setOtherAnnotations(final AnnotationPage... aAnnotationArray) { - return setOtherAnnotations(Arrays.asList(aAnnotationArray)); + public final T setWebAnnotations(final AnnotationPage... aAnnotationArray) { + return setWebAnnotations(Arrays.asList(aAnnotationArray)); } /** @@ -329,8 +328,8 @@ public final T setOtherAnnotations(final AnnotationPage... aAnnot */ @JsonIgnore @SuppressWarnings({ JDK.UNCHECKED }) - public T setOtherAnnotations(final List> aAnnotationList) { - final List> annotations = getOtherAnnotations(); + public T setWebAnnotations(final List> aAnnotationList) { + final List> annotations = getWebAnnotations(); Objects.requireNonNull(aAnnotationList); annotations.clear(); @@ -731,7 +730,7 @@ private List> getAnnotations() { final List> annotations = new ArrayList<>(); getSupplementingPages().forEach(annotations::add); - getOtherAnnotations().forEach(annotations::add); + getWebAnnotations().forEach(annotations::add); return annotations; } @@ -908,7 +907,7 @@ private Minter getMinter(final String aMessageCode) { @JsonSetter(JsonKeys.ANNOTATIONS) private > AbstractCanvas setAnnotations(final Object aObject) { final List> supplementingPages = getSupplementingPages(); - final List> otherAnnotations = getOtherAnnotations(); + final List> otherAnnotations = getWebAnnotations(); final List> annotationList = getDeserializedPageList(aObject); supplementingPages.clear(); diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractContentResource.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractContentResource.java index 154cb36b..adead6d6 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractContentResource.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractContentResource.java @@ -112,7 +112,6 @@ public List> getAnnotations() { * * @return The media type format of the content resource */ - @JsonInclude(Include.NON_EMPTY) @JsonSerialize(contentUsing = MediaTypeSerializer.class, keyUsing = MediaTypeKeySerializer.class) public Optional getFormat() { return Optional.ofNullable(myFormat); @@ -189,7 +188,6 @@ public T setFormat(final MediaType aMediaType) { * @return A form of language ready to be serialized */ @JsonGetter(JsonKeys.LANGUAGE) - @JsonInclude(Include.NON_EMPTY) private Object getLanguage() { final List languages = getLanguages(); return languages.size() == SINGLE_INSTANCE ? languages.get(0) : languages; diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java index 5c2e80bb..0a473b8d 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -14,7 +15,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -229,9 +229,9 @@ public String getID() { * @return The label */ @Override - @JsonUnwrapped - public Label getLabel() { - return myLabel; + @JsonGetter(JsonKeys.LABEL) + public Optional getSummary() { + return Optional.ofNullable(mySummary); } /** @@ -672,6 +672,7 @@ public T setServices(final Service... aServiceArray) { * @return The resource */ @Override + @JsonSetter(JsonKeys.SUMMARY) @SuppressWarnings(JDK.UNCHECKED) public T setSummary(final Summary aSummary) { Objects.requireNonNull(aSummary); diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationCollection.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationCollection.java index 7eabc3d7..6dbe764b 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationCollection.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationCollection.java @@ -92,8 +92,8 @@ public > Optional> getLastPage() { * @return The viewing direction */ @JsonGetter(JsonKeys.VIEWING_DIRECTION) - public ViewingDirection getViewingDirection() { - return myViewingDirection; + public Optional getViewingDirection() { + return Optional.ofNullable(myViewingDirection); } @Override diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java index 55e2152d..73575588 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java @@ -27,10 +27,10 @@ public class Canvas extends AbstractCanvas implements CanvasResource { /** The canvas' accompanying canvas. */ - private Optional myAccompanyingCanvas; + private AccompanyingCanvas myAccompanyingCanvas; /** The canvas' placeholder canvas. */ - private Optional myPlaceholderCanvas; + private PlaceholderCanvas myPlaceholderCanvas; /** * Creates a new canvas, using the supplied minter to create the canvas ID. @@ -104,7 +104,7 @@ public boolean equals(final Object aObject) { @JsonGetter(JsonKeys.ACCOMPANYING_CANVAS) @JsonInclude(Include.NON_ABSENT) public Optional getAccompanyingCanvas() { - return myAccompanyingCanvas; + return Optional.ofNullable(myAccompanyingCanvas); } @Override @@ -124,7 +124,7 @@ public List> getPaintingPages() { @JsonGetter(JsonKeys.PLACEHOLDER_CANVAS) @JsonInclude(Include.NON_ABSENT) public Optional getPlaceholderCanvas() { - return myPlaceholderCanvas; + return Optional.ofNullable(myPlaceholderCanvas); } @Override @@ -204,7 +204,7 @@ public final Canvas paintWith(final String aCanvasRegion, final List> extends Resource * * @return The canvas' non-painting annotation pages */ - List> getOtherAnnotations(); + List> getWebAnnotations(); /** * Gets the canvas' annotation pages for painting annotations. @@ -424,7 +424,7 @@ public interface CanvasResource> extends Resource * @return The canvas */ @SuppressWarnings(JDK.UNCHECKED) - T setOtherAnnotations(AnnotationPage... aAnnotationArray); + T setWebAnnotations(AnnotationPage... aAnnotationArray); /** * Sets the canvas annotation pages from a list. @@ -432,7 +432,7 @@ public interface CanvasResource> extends Resource * @param aAnnotationList A list of annotation pages * @return The canvas */ - T setOtherAnnotations(List> aAnnotationList); + T setWebAnnotations(List> aAnnotationList); /** * Sets the canvas' annotation pages for painting annotations. diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java index 57d41996..6912e21d 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java @@ -17,8 +17,10 @@ import info.freelibrary.util.ListUtils; import info.freelibrary.util.warnings.Eclipse; +import info.freelibrary.util.warnings.JDK; import info.freelibrary.util.warnings.PMD; +import info.freelibrary.iiif.presentation.v3.annotations.WebAnnotation; import info.freelibrary.iiif.presentation.v3.exts.geo.NavPlace; import info.freelibrary.iiif.presentation.v3.ids.UriUtils; import info.freelibrary.iiif.presentation.v3.properties.Behavior; @@ -42,6 +44,9 @@ public class Collection extends NavigableResource implements Resourc /** The collection's accompanying canvas. */ private AccompanyingCanvas myAccompanyingCanvas; + /** The collection's annotations. */ + private List> myAnnotations; + /** The collection's list of items. */ private List myItems; @@ -88,6 +93,7 @@ public boolean equals(final Object aObject) { return Objects.equals(myAccompanyingCanvas, other.myAccompanyingCanvas) && Objects.equals(myPlaceholderCanvas, other.myPlaceholderCanvas) && Objects.equals(myViewingDirection, other.myViewingDirection) && + ListUtils.equals(myAnnotations, other.myAnnotations) && ListUtils.equals(myServiceDefinitions, other.myServiceDefinitions) && ListUtils.equals(myItems, other.myItems) && super.equals(other); } @@ -103,6 +109,21 @@ public Optional getAccompanyingCanvas() { return Optional.ofNullable(myAccompanyingCanvas); } + /** + * Gets the collection's annotation pages. + * + * @return This collection's annotation pages + */ + @JsonGetter(JsonKeys.ANNOTATIONS) + @SuppressWarnings({ JDK.UNCHECKED }) + public List> getAnnotations() { + if (myAnnotations == null) { + myAnnotations = new ArrayList<>(); + } + + return myAnnotations; + } + /** * Gets the primary collection context. * @@ -159,14 +180,14 @@ public List getServiceDefinitions() { * @return The viewing direction */ @JsonGetter(JsonKeys.VIEWING_DIRECTION) - public ViewingDirection getViewingDirection() { - return myViewingDirection; + public Optional getViewingDirection() { + return Optional.ofNullable(myViewingDirection); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), myAccompanyingCanvas, myPlaceholderCanvas, myViewingDirection, - myServiceDefinitions, myItems); + return Objects.hash(super.hashCode(), myAccompanyingCanvas, myPlaceholderCanvas, myAnnotations, + myViewingDirection, myServiceDefinitions, myItems); } /** @@ -181,6 +202,41 @@ public Collection setAccompanyingCanvas(final AccompanyingCanvas aCanvas) { return this; } + /** + * Sets the collection's annotation pages. + * + * @param aPageArray An array of annotation pages + * @return This collection + */ + @SafeVarargs + @JsonIgnore + public final Collection setAnnotations(final AnnotationPage... aPageArray) { + final List> annotations = getAnnotations(); + + Objects.requireNonNull(aPageArray); + annotations.clear(); + Arrays.stream(aPageArray).forEach(annotations::add); + + return this; + } + + /** + * Sets the collection's annotation pages. + * + * @param aPageList A list of annotation pages + * @return This collection + */ + @JsonSetter(JsonKeys.ANNOTATIONS) + public Collection setAnnotations(final List> aPageList) { + final List> annotations = getAnnotations(); + + Objects.requireNonNull(aPageList); + annotations.clear(); + annotations.addAll(aPageList); + + return this; + } + @Override @JsonIgnore public Collection setBehaviors(final Behavior... aBehaviorArray) { @@ -202,6 +258,18 @@ public Collection setBehaviors(final List aBehaviorList) { return collection; } + /** + * Sets the items associated with this collection. + * + * @param anItemArray An array of manifests and/or collections + * @return This collection + */ + @JsonIgnore + public Collection setItems(final Item... anItemArray) { + myItems = Arrays.asList(anItemArray); + return this; + } + /** * Sets the items associated with this collection. * @@ -306,7 +374,7 @@ public Item(final Collection aCollection) { } myType = Item.Type.fromLabel(ResourceTypes.COLLECTION).orElseThrow(); - myLabel = Objects.requireNonNull(aCollection.getLabel()); + aCollection.getLabel().ifPresent(label -> myLabel = label); myID = aCollection.getID(); // ID rules should have been checked by Collection already } @@ -324,7 +392,7 @@ public Item(final Manifest aManifest) { } myType = Item.Type.fromLabel(ResourceTypes.MANIFEST).orElseThrow(); - myLabel = Objects.requireNonNull(aManifest.getLabel()); + aManifest.getLabel().ifPresent(label -> myLabel = label); myID = aManifest.getID(); // ID rules should have been checked by Manifest already } @@ -352,8 +420,8 @@ public String getID() { * @return The item label */ @JsonGetter(JsonKeys.LABEL) - public Label getLabel() { - return myLabel; + public Optional getSummary() { return mySourceCanvas.getSummary(); } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Resource.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Resource.java index a4c5968c..19e39935 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Resource.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Resource.java @@ -2,6 +2,7 @@ package info.freelibrary.iiif.presentation.v3; import java.util.List; +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSetter; @@ -44,9 +45,9 @@ public interface Resource> { List getHomepages(); /** - * Gets the resource ID. + * Gets the ID. * - * @return The resource's ID + * @return The ID */ String getID(); @@ -55,7 +56,7 @@ public interface Resource> { * * @return The resource's label */ - Label getLabel(); + Optional getSummary(); /** * Gets a list of resource thumbnails. A thumbnail can be any type of content resource, not just diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/TextualBody.java b/src/main/java/info/freelibrary/iiif/presentation/v3/TextualBody.java index 6a3ca440..f785ac1a 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/TextualBody.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/TextualBody.java @@ -1,6 +1,8 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.util.Constants.EMPTY; + import java.util.Locale; import java.util.Objects; import java.util.Optional; @@ -89,21 +91,21 @@ public TextualBody(final SkolemIriFactory aFactory) { * @return An optional media type form of format */ @Override - @JsonInclude(Include.NON_EMPTY) @JsonSerialize(contentUsing = MediaTypeSerializer.class, keyUsing = MediaTypeKeySerializer.class) public Optional getFormat() { return Optional.ofNullable(myFormat); } /** - * Gets the ID of the TextualBody if it's serializable; else, it returns a null. + * Gets the ID of the TextualBody if it's serializable and has an ID; else, an empty string is returned. The empty + * string is ignored when the object is serialized to JSON. * * @return A serializable ID */ @Override @JsonGetter(JsonKeys.ID) public String getID() { - return hasSerializableID ? myID : null; + return hasSerializableID && myID != null ? myID : EMPTY; } /** @@ -112,8 +114,8 @@ public String getID() { * @return This TextualBody */ @JsonGetter(JsonKeys.LANGUAGE) - public String getLanguage() { - return myLocale == null ? null : myLocale.toLanguageTag(); + public Optional getLanguage() { + return myLocale == null ? Optional.empty() : Optional.ofNullable(myLocale.toLanguageTag()); } /** @@ -122,8 +124,8 @@ public String getLanguage() { * @return The purpose of the textual body */ @JsonGetter(JsonKeys.PURPOSE) - public Purpose getPurpose() { - return myPurpose; + public Optional getPurpose() { + return Optional.ofNullable(myPurpose); } @Override diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java index 17484450..b1eae6a9 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java @@ -134,27 +134,27 @@ public final void testSetMinter() { } /** - * Tests {@link AbstractCanvas#setOtherAnnotations(AnnotationPage)}. + * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. */ @Test - public final void testSetOtherAnnotations() { + public final void testSetWebAnnotations() { final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); page.addAnnotations(new BookmarkingAnnotation(minter)); - assertEquals(1, new TestClass(minter).setOtherAnnotations(page).getOtherAnnotations().size()); + assertEquals(1, new TestClass(minter).setWebAnnotations(page).getWebAnnotations().size()); } /** - * Tests {@link AbstractCanvas#setOtherAnnotations(AnnotationPage)}. + * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. */ @Test - public final void testSetOtherAnnotationsList() { + public final void testSetWebAnnotationsList() { final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); page.addAnnotations(new BookmarkingAnnotation(minter)); - assertEquals(1, new TestClass(minter).setOtherAnnotations(List.of(page)).getOtherAnnotations().size()); + assertEquals(1, new TestClass(minter).setWebAnnotations(List.of(page)).getWebAnnotations().size()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvasTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvasTest.java index 0ad7bcd1..48a6dac9 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvasTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvasTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -81,7 +82,8 @@ public final void testAccompanyingCanvasMinterLabel() { final Label label = new Label(StringUtils.format(LABEL, id)); final AccompanyingCanvas canvas = new AccompanyingCanvas(minter, label); - assertEquals(StringUtils.format(LABEL, id), canvas.getLabel().getString()); + assertTrue(canvas.getLabel().isPresent()); + assertOptEquals(label, canvas.getLabel()); } /** @@ -122,7 +124,7 @@ public final void testAccompanyingCanvasURILabel() { final AccompanyingCanvas canvas = new AccompanyingCanvas(myID, label); assertEquals(myID, canvas.getID()); - assertEquals(label, canvas.getLabel()); + assertOptEquals(label, canvas.getLabel()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/AnnotationCollectionTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/AnnotationCollectionTest.java index d1a7beb7..7254c26d 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/AnnotationCollectionTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/AnnotationCollectionTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; @@ -159,7 +160,7 @@ public final void testGetSetLastPage() { public void testGetSetViewingDirection() { final AnnotationCollection annotationCollection = new AnnotationCollection(ID, LABEL).setViewingDirection(ViewingDirection.LEFT_TO_RIGHT); - assertEquals(ViewingDirection.LEFT_TO_RIGHT, annotationCollection.getViewingDirection()); + assertOptEquals(ViewingDirection.LEFT_TO_RIGHT, annotationCollection.getViewingDirection()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/CanvasTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/CanvasTest.java index 537576f5..e699b1bc 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/CanvasTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/CanvasTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.format; import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.toJson; import static info.freelibrary.util.Constants.EMPTY; @@ -242,7 +243,7 @@ public final void testCanvasMinterLabel() { final String id = HTTPS + UUID.randomUUID().toString(); final Canvas canvas = new Canvas(MinterFactory.getMinter(id), LABEL); - assertEquals(LABEL, canvas.getLabel()); + assertOptEquals(LABEL, canvas.getLabel()); } /** @@ -264,7 +265,7 @@ public void testConstructorStringLabel() { final Canvas canvas = new Canvas(IMAGE_CANVAS_ID, LABEL); assertEquals(IMAGE_CANVAS_ID, canvas.getID()); - assertEquals(LABEL, canvas.getLabel()); + assertOptEquals(LABEL, canvas.getLabel()); } /** @@ -297,8 +298,7 @@ public final void testGetWidth() { @Test public final void testNavDate() { final NavDate navDate = NavDate.now(); - - assertEquals(navDate, myCanvas.setNavDate(navDate).getNavDate()); + assertOptEquals(navDate, myCanvas.setNavDate(navDate).getNavDate()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java index 75b12a8f..5876dc8a 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.format; import static info.freelibrary.util.Constants.EMPTY; import static org.junit.Assert.assertEquals; @@ -143,7 +144,7 @@ public final void testCollectionItemCollection() { final Collection.Item item = new Collection.Item(collection); assertEquals(myID, item.getID()); - assertEquals(myLabel, item.getLabel()); + assertOptEquals(myLabel, item.getLabel()); assertEquals(1, item.getThumbnails().size()); } @@ -156,7 +157,7 @@ public final void testCollectionItemManifest() { final Collection.Item item = new Collection.Item(manifest); assertEquals(myID, item.getID()); - assertEquals(myLabel, item.getLabel()); + assertOptEquals(myLabel, item.getLabel()); assertEquals(1, item.getThumbnails().size()); } @@ -171,7 +172,7 @@ public final void testCollectionItemSetThumbnails() { item.setThumbnails(new ImageContent(myID)); assertEquals(myID, item.getID()); - assertEquals(myLabel, item.getLabel()); + assertOptEquals(myLabel, item.getLabel()); assertEquals(1, item.getThumbnails().size()); } @@ -183,7 +184,7 @@ public void testCollectionManifestManifestConstructor() { final Collection.Item item = new Collection.Item(new Manifest(myID, myLabel)); assertEquals(myID, item.getID()); - assertEquals(myLabel, item.getLabel()); + assertOptEquals(myLabel, item.getLabel()); } /** @@ -232,7 +233,7 @@ public void testNavDate1() { final NavDate navDate = NavDate.now(); collection.setNavDate(navDate); - assertEquals(navDate, collection.getNavDate()); + assertOptEquals(navDate, collection.getNavDate()); } /** @@ -245,7 +246,7 @@ public void testNavDate2() { final NavDate navDate = new NavDate(zonedDateTime); collection.setNavDate(navDate); - assertEquals(navDate, collection.getNavDate()); + assertOptEquals(navDate, collection.getNavDate()); } /** @@ -283,8 +284,9 @@ public final void testSetDisallowedBehaviors() { public final void testSetNavPlace() { final Manifest manifest = new Manifest(myID, myLabel); final Collection.Item item = new Collection.Item(manifest); + final NavPlace navPlace = new NavPlace(myID); - assertEquals(myID, item.setNavPlace(new NavPlace(myID)).getNavPlace().getID()); + assertOptEquals(navPlace, item.setNavPlace(navPlace).getNavPlace()); } /** @@ -312,7 +314,7 @@ public final void testSetServiceDefinitionsList() { */ @Test public final void testSetViewingDirection() { - assertEquals(ViewingDirection.TOP_TO_BOTTOM, new Collection(myID, myLabel) + assertOptEquals(ViewingDirection.TOP_TO_BOTTOM, new Collection(myID, myLabel) .setViewingDirection(ViewingDirection.TOP_TO_BOTTOM).getViewingDirection()); } diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ImageContentTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ImageContentTest.java index 482f9ee3..8368dfef 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ImageContentTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ImageContentTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static info.freelibrary.util.Constants.EMPTY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -217,8 +218,7 @@ public void testSetHeightInt() { @Test public void testSetLabel() { final Label label = new Label("MY LABEL"); - - assertEquals(label, new ImageContent(IMAGE_URI).setLabel(label).getLabel()); + assertOptEquals(label, new ImageContent(IMAGE_URI).setLabel(label).getLabel()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java index c6be2400..6ea6bc34 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java @@ -110,6 +110,7 @@ public void setUp() throws IOException { final List firstCanvas = reader1.readAll(); final List secondCanvas = reader2.readAll(); final List metadata = new ArrayList<>(); + final List canvases = new ArrayList<>(); final ImageService3 manifestThumbService; reader1.close(); @@ -138,7 +139,7 @@ public void setUp() throws IOException { new AnnotationPage<>(MANIFEST_SERVER + MANIFEST_ID + "/pageanno/pageanno-2"); canvas1.getPaintingPages().add(page1.addAnnotations(content1)); - myManifest.addCanvases(canvas1); + canvases.add(canvas1); for (final String[] values : firstCanvas) { final String id = MANIFEST_SERVER + values[1] + MANIFEST_THUMBNAIL_PATH; @@ -160,7 +161,7 @@ public void setUp() throws IOException { content2 = new PaintingAnnotation(MANIFEST_SERVER + MANIFEST_ID + "/imageanno/imageanno-2", canvas2); canvas2.getPaintingPages().add(page2.addAnnotations(content2)); - myManifest.addCanvases(canvas2); + canvases.add(canvas2); for (final String[] values : secondCanvas) { final String id = MANIFEST_SERVER + values[1] + MANIFEST_THUMBNAIL_PATH; @@ -177,6 +178,7 @@ public void setUp() throws IOException { myManifest.setRights("http://creativecommons.org/licenses/by/4.0/").setBehaviors(ManifestBehavior.PAGED) .setRequiredStatement(reqStmt).setServices(otherService); + myManifest.setCanvases(canvases); } /** @@ -186,7 +188,7 @@ public void setUp() throws IOException { public void testAddRanges() { final Range range = new Range(HTTPS + UUID.randomUUID().toString()); - myManifest.addRanges(range); + myManifest.setRanges(range); assertEquals(1, myManifest.getRanges().size()); } @@ -197,7 +199,7 @@ public void testAddRanges() { public void testAddRangesList() { final Range range = new Range(HTTPS + UUID.randomUUID().toString()); - myManifest.addRanges(List.of(range)); + myManifest.setRanges(List.of(range)); assertEquals(1, myManifest.getRanges().size()); } @@ -255,7 +257,8 @@ public final void testComparatorSort() { public void testConstructorStringLabel() { myManifest = new Manifest(MANIFEST_URI, new Label(METADATA_PAIRS.get(0)[1])); assertEquals(MANIFEST_URI, myManifest.getID()); - assertEquals(METADATA_PAIRS.get(0)[1], myManifest.getLabel().getString()); + assertTrue(myManifest.getLabel().isPresent()); + assertEquals(METADATA_PAIRS.get(0)[1], myManifest.getLabel().get().getString()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvasTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvasTest.java index 7891d319..c20a25e0 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvasTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvasTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -283,7 +284,7 @@ public final void testPlaceholderCanvasURILabel() { final PlaceholderCanvas canvas = new PlaceholderCanvas(myID, label); assertEquals(myID, canvas.getID()); - assertEquals(label, canvas.getLabel()); + assertOptEquals(label, canvas.getLabel()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/RangeTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/RangeTest.java index 0d006b5e..c82ce4e7 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/RangeTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/RangeTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -158,7 +159,7 @@ public void testGetSetSupplementaryAnnotations() throws JsonProcessingException @Test public void testGetSetViewingDirection() { final Range range = getRange().setViewingDirection(ViewingDirection.LEFT_TO_RIGHT); - assertEquals(ViewingDirection.LEFT_TO_RIGHT, range.getViewingDirection()); + assertOptEquals(ViewingDirection.LEFT_TO_RIGHT, range.getViewingDirection()); } /** @@ -175,7 +176,7 @@ public void testGetStart() { @Test public final void testNavDate() { final NavDate navDate = NavDate.now(); - assertEquals(navDate, getRange().setNavDate(navDate).getNavDate()); + assertOptEquals(navDate, getRange().setNavDate(navDate).getNavDate()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/TextualBodyTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/TextualBodyTest.java index 69996639..e02dff0d 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/TextualBodyTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/TextualBodyTest.java @@ -1,6 +1,8 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.utils.TestUtils.assertOptEquals; +import static info.freelibrary.util.Constants.EMPTY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -61,7 +63,7 @@ public final void testSerializedID() { @Test public final void testSetGetLanguage() { final String language = "fr"; - assertEquals(language, new TextualBody().setLanguage(language).getLanguage()); + assertOptEquals(language, new TextualBody().setLanguage(language).getLanguage()); } /** @@ -78,7 +80,7 @@ public final void testSetGetValue() { */ @Test public final void testTextualBody() { - assertEquals(null, new TextualBody().getID()); + assertEquals(EMPTY, new TextualBody().getID()); } /** @@ -110,6 +112,6 @@ public final void testToString() throws IOException { @Test public final void testUnserializeID() { final TextualBody textualBody = new TextualBody(SkolemIriFactory.getFactory()).serializeID(false); - assertEquals(null, textualBody.getID()); + assertEquals(EMPTY, textualBody.getID()); } } diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/examples/CookbooksTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/examples/CookbooksTest.java index 144a6e8c..fded4baf 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/examples/CookbooksTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/examples/CookbooksTest.java @@ -301,7 +301,7 @@ public final void test0005WithMinter() throws IOException { imageContent.setWidthHeight(4032, 3024).setFormat(IMAGE_JPEG).setServices(service); canvas.setWidthHeight(4032, 3024).paintWith(imageContent); - manifest.addCanvases(canvas); + manifest.setCanvases(canvas); System.out.println(manifest); @@ -376,7 +376,7 @@ public final void test0006WithMinter() throws IOException { manifest.setRequiredStatement(new RequiredStatement(reqStmtLabel, reqStmt)); imageContent.setWidthHeight(1114, 991).setFormat(IMAGE_JPEG).setServices(service); - manifest.addCanvases(canvas.setWidthHeight(1114, 991).paintWith(imageContent)); + manifest.setCanvases(canvas.setWidthHeight(1114, 991).paintWith(imageContent)); System.out.println(manifest); @@ -421,7 +421,7 @@ public final void test0006WithMinterAndMatrix() throws IOException { manifest.setRequiredStatement(reqStatement); imageContent.setWidthHeight(1114, 991).setFormat(IMAGE_JPEG).setServices(service); - manifest.addCanvases(canvas.setWidthHeight(1114, 991).paintWith(imageContent)); + manifest.setCanvases(canvas.setWidthHeight(1114, 991).paintWith(imageContent)); System.out.println(manifest); @@ -470,7 +470,7 @@ public final void test0006WithoutMinter() throws IOException { imageContent.setWidthHeight(1114, 991).setFormat(IMAGE_JPEG).setServices(service); page.addAnnotations(annotation.setBody(imageContent).setTarget(new Target(canvas))); - manifest.addCanvases(canvas.setWidthHeight(1114, 991).setPaintingPages(page)); + manifest.setCanvases(canvas.setWidthHeight(1114, 991).setPaintingPages(page)); System.out.println(manifest); @@ -503,7 +503,7 @@ public final void test0007WithMinter() throws IOException { "Glen Robson, IIIF Technical Coordinator. CC BY-SA 3.0 "))); imageContent.setWidthHeight(4032, 3024).setFormat(IMAGE_JPEG).setServices(service); - manifest.addCanvases(canvas.setWidthHeight(4032, 3024).paintWith(imageContent)); + manifest.setCanvases(canvas.setWidthHeight(4032, 3024).paintWith(imageContent)); System.out.println(manifest); @@ -540,7 +540,7 @@ public final void test0007WithoutMinter() throws IOException { imageContent.setWidthHeight(4032, 3024).setFormat(IMAGE_JPEG).setServices(service); page.addAnnotations(annotation.setBody(imageContent).setTarget(new Target(canvas))); - manifest.addCanvases(canvas.setWidthHeight(4032, 3024).setPaintingPages(page)); + manifest.setCanvases(canvas.setWidthHeight(4032, 3024).setPaintingPages(page)); System.out.println(manifest); @@ -571,7 +571,7 @@ public final void test0008WithMinter() throws IOException { "Glen Robson, IIIF Technical Coordinator. CC BY-SA 3.0 "))); imageContent.setWidthHeight(4032, 3024).setFormat(IMAGE_JPEG).setServices(service); - manifest.addCanvases(canvas.setWidthHeight(4032, 3024).paintWith(imageContent)); + manifest.setCanvases(canvas.setWidthHeight(4032, 3024).paintWith(imageContent)); System.out.println(manifest); @@ -606,7 +606,7 @@ public final void test0008WithoutMinter() throws IOException { imageContent.setWidthHeight(4032, 3024).setFormat(IMAGE_JPEG).setServices(service); page.addAnnotations(annotation.setBody(imageContent).setTarget(new Target(canvas))); - manifest.addCanvases(canvas.setWidthHeight(4032, 3024).setPaintingPages(page)); + manifest.setCanvases(canvas.setWidthHeight(4032, 3024).setPaintingPages(page)); System.out.println(manifest); @@ -676,7 +676,7 @@ public final void test0009WithMinter() throws IOException { imageContent5.setWidthHeight(3198, 4632).setFormat(IMAGE_JPEG).setServices(service5); canvas5.setWidthHeight(3198, 4632).paintWith(imageContent5); - manifest.addCanvases(canvas1, canvas2, canvas3, canvas4, canvas5); + manifest.setCanvases(canvas1, canvas2, canvas3, canvas4, canvas5); System.out.println(manifest); @@ -730,7 +730,7 @@ public final void test0009WithMinterLooped() throws IOException { }); manifest.setBehaviors(PAGED); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); @@ -790,7 +790,7 @@ public final void test0009WithoutMinterLooped() throws IOException { } manifest.setBehaviors(PAGED); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); @@ -847,7 +847,7 @@ public final void test0010WithMinterLoopedRTL() throws IOException { manifest.setSummary(new Summary("en", "Playbill for \"Akiba gongen kaisen-banashi,\" \"Futatsu chōchō kuruwa nikki\" and \"Godairiki koi no fūjime\" performed at the Chikugo Theater in Osaka from the fifth month of Kaei 2 (May, 1849); main actors: Gadō Kataoka II, Ebizō Ichikawa VI, Kitō Sawamura II, Daigorō Mimasu IV and Karoku Nakamura I; on front cover: producer Mominosuke Ichikawa's crest.")); manifest.setViewingDirection(RIGHT_TO_LEFT); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); @@ -899,7 +899,7 @@ public final void test0010WithMinterLoopedTTB() throws IOException { manifest.setSummary(new Summary("en", "William Lewis Sachtleben was an American long-distance cyclist who rode across Asia from Istanbul to Peking in 1891 to 1892 with Thomas Gaskell Allen Jr., his classmate from Washington University. This was part of a longer journey that began the day after they had graduated from college, when they travelled to New York and on to Liverpool; in all they travelled 15,044 miles by bicycle, 'the longest continuous land journey ever made around the world' as reported in their book Across Asia on a bicycle (1895). Sachtleben documented his travels with photographs and diaries, the latter of which he numbered sequentially. The diary of notebook 'No. 10' covers a portion of their journey through the Armenian area of Turkey from April 12 to May 9 (there is a 2-page reading list at the end). During this time they rode from Ankara (Angora in the diary) to Sivas, where they stayed for ten days while Allen had a bout of typhoid fever, and the first half of a ten-day excursion to Merzifon (Mersovan in the diary), taken by Sachtleben to give Allen additional time to recover.")); manifest.setViewingDirection(TOP_TO_BOTTOM); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); @@ -972,7 +972,7 @@ public final void test0010WithMinterRTL() throws IOException { imageContent5.setWidthHeight(3510, 4808).setFormat(IMAGE_JPEG).setServices(service5); canvas5.setWidthHeight(3510, 4808).paintWith(imageContent5); - manifest.addCanvases(canvas1, canvas2, canvas3, canvas4, canvas5); + manifest.setCanvases(canvas1, canvas2, canvas3, canvas4, canvas5); System.out.println(manifest); @@ -1035,7 +1035,7 @@ public final void test0010WithMinterTTB() throws IOException { imageContent4.setWidthHeight(2268, 3135).setFormat(IMAGE_JPEG).setServices(service4); canvas4.setWidthHeight(2268, 3135).paintWith(imageContent4); - manifest.addCanvases(canvas1, canvas2, canvas3, canvas4); + manifest.setCanvases(canvas1, canvas2, canvas3, canvas4); System.out.println(manifest); @@ -1101,7 +1101,7 @@ public final void test0010WithoutMinterLoopedRTL() throws IOException { manifest.setSummary(new Summary("en", "Playbill for \"Akiba gongen kaisen-banashi,\" \"Futatsu chōchō kuruwa nikki\" and \"Godairiki koi no fūjime\" performed at the Chikugo Theater in Osaka from the fifth month of Kaei 2 (May, 1849); main actors: Gadō Kataoka II, Ebizō Ichikawa VI, Kitō Sawamura II, Daigorō Mimasu IV and Karoku Nakamura I; on front cover: producer Mominosuke Ichikawa's crest.")); manifest.setViewingDirection(RIGHT_TO_LEFT); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); @@ -1162,7 +1162,7 @@ public final void test0010WithoutMinterLoopedTTB() throws IOException { manifest.setSummary(new Summary("en", "William Lewis Sachtleben was an American long-distance cyclist who rode across Asia from Istanbul to Peking in 1891 to 1892 with Thomas Gaskell Allen Jr., his classmate from Washington University. This was part of a longer journey that began the day after they had graduated from college, when they travelled to New York and on to Liverpool; in all they travelled 15,044 miles by bicycle, 'the longest continuous land journey ever made around the world' as reported in their book Across Asia on a bicycle (1895). Sachtleben documented his travels with photographs and diaries, the latter of which he numbered sequentially. The diary of notebook 'No. 10' covers a portion of their journey through the Armenian area of Turkey from April 12 to May 9 (there is a 2-page reading list at the end). During this time they rode from Ankara (Angora in the diary) to Sivas, where they stayed for ten days while Allen had a bout of typhoid fever, and the first half of a ten-day excursion to Merzifon (Mersovan in the diary), taken by Sachtleben to give Allen additional time to recover.")); manifest.setViewingDirection(TOP_TO_BOTTOM); - manifest.addCanvases(canvases); + manifest.setCanvases(canvases); System.out.println(manifest); diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ids/DefaultMinterTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ids/DefaultMinterTest.java index 27704e0c..a760e9f0 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ids/DefaultMinterTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ids/DefaultMinterTest.java @@ -135,7 +135,7 @@ public final void testIteratorHasNext() { public final void testManifestConstructor() { final String id = myManifestID + "/canvas-kfb9"; final Manifest manifest = new Manifest(myManifestID, new Label("Label")); - final Minter minter = MinterFactory.getMinter(manifest.addCanvases(new Canvas(id))); + final Minter minter = MinterFactory.getMinter(manifest.setCanvases(new Canvas(id))); int counter = 0; diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ids/SkolemIriFactoryTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ids/SkolemIriFactoryTest.java index da8ac363..fd4c8ba1 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ids/SkolemIriFactoryTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ids/SkolemIriFactoryTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3.ids; +import static info.freelibrary.util.Constants.EMPTY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -68,7 +69,7 @@ public final void testGetSkolemIRI() { */ @Test public final void testHasNonSerializableIDs() { - assertEquals(null, new TextualBody(SkolemIriFactory.getFactory().createSerializableIDs(false)).getID()); + assertEquals(EMPTY, new TextualBody(SkolemIriFactory.getFactory().createSerializableIDs(false)).getID()); } /** @@ -76,7 +77,7 @@ public final void testHasNonSerializableIDs() { */ @Test public final void testHasNonSerializableIDsDefault() { - assertEquals(null, + assertEquals(EMPTY, new TextualBody(SkolemIriFactory.getFactory().createSerializableIDs(false).setWellKnownBase(null)) .getID()); } @@ -86,7 +87,7 @@ public final void testHasNonSerializableIDsDefault() { */ @Test public final void testHasSerializableIDs() { - assertNotEquals(null, new TextualBody(SkolemIriFactory.getFactory().createSerializableIDs(true)).getID()); + assertNotEquals(EMPTY, new TextualBody(SkolemIriFactory.getFactory().createSerializableIDs(true)).getID()); } /** From f42e9edcea09a4fdea95b58b346d44a7dc43d5eb Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Mon, 2 Sep 2024 00:50:45 -0400 Subject: [PATCH 2/8] WIP --- .../iiif/presentation/v3/AbstractCanvas.java | 105 +++-- .../presentation/v3/AbstractResource.java | 4 - .../presentation/v3/AccompanyingCanvas.java | 5 - .../iiif/presentation/v3/AnnotationPage.java | 12 +- .../iiif/presentation/v3/Canvas.java | 5 - .../iiif/presentation/v3/Collection.java | 14 +- .../iiif/presentation/v3/ContextList.java | 366 ++++++++++++++++++ .../iiif/presentation/v3/Manifest.java | 14 +- .../presentation/v3/NavigableResource.java | 212 ++-------- .../presentation/v3/PlaceholderCanvas.java | 5 - .../iiif/presentation/v3/Range.java | 13 - .../iiif/presentation/v3/RangeCanvas.java | 35 +- .../utils/json/ContextListDeserializer.java | 66 ++++ .../v3/utils/json/ContextListSerializer.java | 58 +++ .../resources/iiif_presentation_messages.xml | 4 + .../presentation/v3/AbstractCanvasTest.java | 53 ++- .../iiif/presentation/v3/CollectionTest.java | 8 - .../iiif/presentation/v3/ContextListTest.java | 283 ++++++++++++++ .../iiif/presentation/v3/ManifestTest.java | 85 ---- 19 files changed, 897 insertions(+), 450 deletions(-) create mode 100644 src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java create mode 100644 src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java create mode 100644 src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java create mode 100644 src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java index c54171ca..f2be3981 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractCanvas.java @@ -74,15 +74,15 @@ abstract class AbstractCanvas> extends NavigableReso /** The canvas' optional minter. */ private Minter myMinter; - /** The canvas' other canvases (other than painting or supplementing). */ - private List> myWebAnnotations; - /** The painting annotations on the canvas. */ private List> myPaintingPageList; /** The supplementing annotations on the canvas. */ private List> mySupplementingPageList; + /** The canvas' other canvases (other than painting or supplementing). */ + private List> myWebAnnotations; + /** The canvas' width. */ private int myWidth; @@ -186,20 +186,6 @@ public Optional getMinter() { return Optional.ofNullable(myMinter); } - /** - * Gets the canvas' annotation pages that aren't related to painting. - * - * @return The canvas' non-painting annotation pages - */ - @JsonIgnore - public List> getWebAnnotations() { - if (myWebAnnotations == null) { - myWebAnnotations = new ArrayList<>(); - } - - return myWebAnnotations; - } - /** * Gets the canvas' annotation pages for painting annotations. * @@ -229,6 +215,20 @@ public List> getSupplementingPages() { return mySupplementingPageList; } + /** + * Gets the canvas' annotation pages that aren't related to painting. + * + * @return The canvas' non-painting annotation pages + */ + @JsonIgnore + public List> getWebAnnotations() { + if (myWebAnnotations == null) { + myWebAnnotations = new ArrayList<>(); + } + + return myWebAnnotations; + } + /** * Gets the width of the canvas. * @@ -308,36 +308,6 @@ public T setMinter(final Minter aMinter) { return (T) this; } - /** - * Sets the canvas' annotation pages from an array. - * - * @param aAnnotationArray An array of annotation pages - * @return The canvas - */ - @JsonIgnore - @SafeVarargs - public final T setWebAnnotations(final AnnotationPage... aAnnotationArray) { - return setWebAnnotations(Arrays.asList(aAnnotationArray)); - } - - /** - * Sets the canvas annotation pages from a list. - * - * @param aAnnotationList A list of annotation pages - * @return The canvas - */ - @JsonIgnore - @SuppressWarnings({ JDK.UNCHECKED }) - public T setWebAnnotations(final List> aAnnotationList) { - final List> annotations = getWebAnnotations(); - - Objects.requireNonNull(aAnnotationList); - annotations.clear(); - annotations.addAll(aAnnotationList); - - return (T) this; - } - /** * Sets the canvas' painting pages. * @@ -408,6 +378,36 @@ public T setSupplementingPages(final List... aAnnotationArray) { + return setWebAnnotations(Arrays.asList(aAnnotationArray)); + } + + /** + * Sets the canvas annotation pages from a list. + * + * @param aAnnotationList A list of annotation pages + * @return The canvas + */ + @JsonIgnore + @SuppressWarnings({ JDK.UNCHECKED }) + public T setWebAnnotations(final List> aAnnotationList) { + final List> annotations = getWebAnnotations(); + + Objects.requireNonNull(aAnnotationList); + annotations.clear(); + annotations.addAll(aAnnotationList); + + return (T) this; + } + /** * Sets the width and height of the canvas. * @@ -429,17 +429,6 @@ public T setWidthHeight(final int aWidth, final int aHeight) { return (T) this; } - /** - * Gets the manifest context. The manifest can either have a single context or an array of contexts (Cf. - * https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions) - * - * @return The manifest context - */ - @Override - @JsonGetter(JsonKeys.CONTEXT) - @JsonInclude(Include.NON_NULL) - protected abstract Object getJsonContext(); - /** * Paints a canvas, that has been initialized with a minter, with the supplied content resources. If the canvas was * not initialized with a minter, a {@code MintingException} is thrown. diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java index 0a473b8d..2b6a2913 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AbstractResource.java @@ -1,7 +1,6 @@ package info.freelibrary.iiif.presentation.v3; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -54,9 +53,6 @@ JsonKeys.ITEMS, JsonKeys.SERVICE, JsonKeys.STRUCTURES, JsonKeys.SERVICES, JsonKeys.NAV_DATE, JsonKeys.ANNOTATIONS }) abstract class AbstractResource> implements Resource { - /** The IIIF Presentation context URI. */ - protected static final URI PRESENTATION_CONTEXT_URI = URI.create("http://iiif.io/api/presentation/3/context.json"); - /** The logger used by abstract resources. */ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractResource.class, MessageCodes.BUNDLE); diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvas.java index 14ee1f1f..81e61a9f 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AccompanyingCanvas.java @@ -210,9 +210,4 @@ public final AccompanyingCanvas supplementWith(final String aCanvasRegion, final List aContentList) { return super.supplement(this, new MediaFragmentSelector(aCanvasRegion), false, aContentList); } - - @Override - protected Object getJsonContext() { - return null; - } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationPage.java b/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationPage.java index 3aae80a7..27d5028c 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationPage.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/AnnotationPage.java @@ -11,6 +11,8 @@ import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonSetter; import info.freelibrary.util.Logger; @@ -33,6 +35,7 @@ * @param The type of annotation encapsulated on the page */ @SuppressWarnings({ PMD.GOD_CLASS, PMD.EXCESSIVE_IMPORTS, PMD.COUPLING_BETWEEN_OBJECTS }) +@JsonInclude(Include.NON_EMPTY) public class AnnotationPage> extends AbstractResource> implements Resource> { @@ -256,13 +259,14 @@ public > AnnotationPage setNextPage(final AnnotationP } /** - * Gets the context when the annotation page is intended to be used outside of a manifest. + * Gets the context only when the annotation page is intended to be used outside of a manifest, as indicated by + * using {@code AnnotationPage#setExternalContext()}. * * @return The context URI */ @JsonGetter(JsonKeys.CONTEXT) - private URI getExternalContext() { - return isExternal ? PRESENTATION_CONTEXT_URI : null; + private Optional getExternalContext() { + return isExternal ? Optional.of(ContextList.PRESENTATION_CONTEXT_URI) : Optional.empty(); } /** @@ -293,7 +297,7 @@ private String getListIDs(final List aAnnotationList) { */ @JsonSetter(JsonKeys.CONTEXT) private AnnotationPage setExternalContext(final String aContextURI) { - if (PRESENTATION_CONTEXT_URI.toString().equalsIgnoreCase(aContextURI)) { + if (ContextList.PRESENTATION_CONTEXT_URI.toString().equalsIgnoreCase(aContextURI)) { setExternalContext(); } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java index 73575588..593dad97 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Canvas.java @@ -291,9 +291,4 @@ public final Canvas supplementWith(final String aCanvasRegion, final ContentReso public final Canvas supplementWith(final String aCanvasRegion, final List aContentList) { return super.supplement(this, new MediaFragmentSelector(aCanvasRegion), false, aContentList); } - - @Override - protected Object getJsonContext() { - return null; - } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java index 6912e21d..ddd86b03 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Collection.java @@ -1,7 +1,6 @@ package info.freelibrary.iiif.presentation.v3; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -67,6 +66,7 @@ public class Collection extends NavigableResource implements Resourc */ public Collection(final String aID, final Label aLabel) { super(ResourceTypes.COLLECTION, aID, aLabel, CollectionBehavior.class); + getContextList(); // Initializes the context list } /** @@ -74,6 +74,7 @@ public Collection(final String aID, final Label aLabel) { */ private Collection() { super(ResourceTypes.COLLECTION, CollectionBehavior.class); + getContextList(); // Initializes the context list } @Override @@ -124,17 +125,6 @@ public List> getAnnotations() { return myAnnotations; } - /** - * Gets the primary collection context. - * - * @return The collection context - */ - @Override - @JsonIgnore - public URI getContext() { - return PRESENTATION_CONTEXT_URI; - } - /** * Gets the items associated with this collection. * diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java new file mode 100644 index 00000000..5506f7f4 --- /dev/null +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java @@ -0,0 +1,366 @@ + +package info.freelibrary.iiif.presentation.v3; + +import static info.freelibrary.util.Constants.SINGLE_INSTANCE; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import info.freelibrary.util.Logger; +import info.freelibrary.util.LoggerFactory; +import info.freelibrary.util.warnings.PMD; + +import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; + +/** + * A list of context URIs. + */ +public class ContextList extends ArrayList implements List { + + /** The IIIF Presentation context URI. */ + public static final URI PRESENTATION_CONTEXT_URI = URI.create("http://iiif.io/api/presentation/3/context.json"); + + /** The {@code ContextList} logger. */ + private static final Logger LOGGER = LoggerFactory.getLogger(ContextList.class, MessageCodes.BUNDLE); + + /** The context list's serialVersionUID. */ + private static final long serialVersionUID = -877433424933939199L; + + /** A simple sorter that only moves the required context to the first slot. */ + private final Comparator myComparator; + + /** + * Creates a new list of contexts. It includes the IIIF Presentation context by default. + */ + public ContextList() { + super(); + + myComparator = new ContextListComparator(); + super.add(0, PRESENTATION_CONTEXT_URI); + } + + /** + * Creates a new list of contexts. A {@code ContextList} includes the IIIF Presentation context by default. If one + * is included in the supplied list, it will be ignored so it's not duplicated. + * + * @param aUriList A list of context URIs + */ + public ContextList(final List aUriList) { + super(); + + myComparator = new ContextListComparator(); + super.addAll(aUriList); + + if (!super.contains(PRESENTATION_CONTEXT_URI)) { + super.add(0, PRESENTATION_CONTEXT_URI); + } else { + super.sort(myComparator); + } + } + + /** + * Adds a new context URI at the supplied index position. If the supplied context is not the IIIF Presentation + * context and the supplied index position is zero, it will be added at position one instead. Only the default + * context lives at position zero. + * + * @param aIndex An index position at which to add the supplied URI + * @param aURI A URI to add at the supplied index position + */ + @Override + public void add(final int aIndex, final URI aURI) { + if (!PRESENTATION_CONTEXT_URI.equals(aURI)) { + if (aIndex == 0) { + super.add(1, aURI); + LOGGER.warn(MessageCodes.JPA_150, aURI); + } else { + super.add(aIndex, aURI); + } + } + } + + /** + * Adds the supplied context URI. This will return false if the supplied URI is the default IIIF Presentation + * context or if the supplied context could not be added for any other reason. + * + * @param aURI A URI to add to the list + * @return True if the supplied URI was successfully added to the list + */ + @Override + public boolean add(final URI aURI) { + return !PRESENTATION_CONTEXT_URI.equals(aURI) && super.add(aURI); + } + + /** + * Adds all the supplied context URIs. If the supplied collection contains the default IIIF Presentation context, + * all contexts except for that one will be added. The default context is ignored because it already exists in the + * context list. + * + * @param aUriCollection A collection of context URIs + * @return True if all the URIs were added to the list + */ + @Override + public boolean addAll(final Collection aUriCollection) { + return aUriCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).allMatch(super::add); + } + + /** + * Adds all the supplied context URIs. If the supplied collection contains the default IIIF Presentation context, + * all contexts except for that one will be added. The default context is ignored because it already exists in the + * context list. + * + * @param aIndex An index position at which to add the URIs in the supplied collection + * @param aUriCollection A collection of URIs to add at the supplied index position + * @return If all the supplied URIs were successfully added + */ + @Override + public boolean addAll(final int aIndex, final Collection aUriCollection) { + if (aUriCollection.contains(PRESENTATION_CONTEXT_URI)) { + aUriCollection.remove(PRESENTATION_CONTEXT_URI); + } + + return super.addAll(aIndex, aUriCollection); + } + + /** + * If the supplied URI is not the default IIIF Presentation context, it is added at index position one. The first + * index position (i.e., zero) is reserved for the default IIIF Presentation context. + * + * @param aURI A context URI to add at the beginning of the list + */ + @SuppressWarnings(PMD.MISSING_OVERRIDE) + public void addFirst(final URI aURI) { + if (!PRESENTATION_CONTEXT_URI.equals(aURI)) { + super.add(1, aURI); + } // Ignore if passing the default URI, because that already lives at index position zero + } + + /** + * Adds the supplied context URI as the last in the list, unless the supplied context is the default IIIF + * Presentation context (in which case it's ignored -- the list already contains the default context). + * + * @param aURI A context URI to add at the end of the list + */ + @SuppressWarnings(PMD.MISSING_OVERRIDE) + public void addLast(final URI aURI) { + if (!PRESENTATION_CONTEXT_URI.equals(aURI)) { + super.add(aURI); // Adding, by default, adds as the last item + } else { + LOGGER.warn(MessageCodes.JPA_149); + } + } + + /** + * Clears all contexts except for the IIIF Presentation context URI, which must always exist in the list. + */ + @Override + public void clear() { + super.clear(); + super.add(0, PRESENTATION_CONTEXT_URI); + } + + @Override + public boolean equals(final Object aObject) { + final ContextList other; + + if (this == aObject) { + return true; + } + + if (aObject == null || getClass() != aObject.getClass()) { + return false; + } + + other = (ContextList) aObject; + + return Arrays.equals(other.toArray(), super.toArray()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(super.toArray()); + } + + /** + * Removes the context URI at the supplied index position, unless the position is zero. In this case, an + * {@link IndexOutOfBoundsException} is thrown because it is out of bounds of the URIs that can be removed. + * + * @param aIndex The index position of the URI to remove from the list + * @return The URI removed from the list + */ + @Override + public URI remove(final int aIndex) { + if (aIndex == 0) { + throw new IndexOutOfBoundsException(LOGGER.getMessage(MessageCodes.JPA_039, PRESENTATION_CONTEXT_URI)); + } + + return super.remove(aIndex); + } + + /** + * Removes the supplied context URI unless it: is the default IIIF Presentation context URI, is another type of + * object, or is a context URI that doesn't exist in the list. + * + * @param aObj A URI to remove from the list + * @return True if the supplied URI was removed + */ + @Override + public boolean remove(final Object aObj) { + return !PRESENTATION_CONTEXT_URI.equals(aObj) && super.remove(aObj); + } + + /** + * Removes all the contexts in the supplied collection. If the IIIF Presentation context URI is included in the + * collection, it is ignored. It cannot be removed. + * + * @param aCollection A collection of URIs to remove + * @return True if the URIs were removed + */ + @Override + public boolean removeAll(final Collection aCollection) { + if (aCollection.contains(PRESENTATION_CONTEXT_URI)) { + final Stream stream = aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)); + final List removables = stream.collect(Collectors.toList()); + + return super.removeAll(removables); + } + + return super.removeAll(aCollection); + } + + /** + * Removes a context that's selected by the supplied filter. If the default context is removed by the filter, it + * will be automatically added back at index position zero. + * + * @param aFilter A filter to use to remove URIs from the list + * @return True if the URIs were removed + */ + @SuppressWarnings(PMD.MISSING_OVERRIDE) + public boolean removeIf(final Predicate aFilter) { + final boolean result = super.removeIf(aFilter); + + // If the filter removes our required default context, we add it back + if (!PRESENTATION_CONTEXT_URI.equals(get(0))) { + super.add(0, PRESENTATION_CONTEXT_URI); + } + + return result; + } + + /** + * Removes the last context URI, unless the last URI is the default context. In that case, a + * {@link NoSuchElementException} is thrown. + * + * @return The context URI that was removed + * @throws NoSuchElementException If the list only has the required IIIF Presentation context + */ + @SuppressWarnings(PMD.MISSING_OVERRIDE) + public URI removeLast() { + if (size() == SINGLE_INSTANCE) { + throw new NoSuchElementException(LOGGER.getMessage(MessageCodes.JPA_039, PRESENTATION_CONTEXT_URI)); + } + + return remove(size() - 1); + } + + /** + * Replaces contexts in the list according to the supplied operator. + * + * @param anOperator A UnaryOperator to use in replacing URIs + */ + @Override + public void replaceAll(final UnaryOperator anOperator) { + super.replaceAll(anOperator); + + // Remove all instances of our default context URI + super.removeAll(List.of(PRESENTATION_CONTEXT_URI)); + + // Add back a single instance of our default context URI + if (!PRESENTATION_CONTEXT_URI.equals(get(0))) { + super.add(0, PRESENTATION_CONTEXT_URI); + } + } + + /** + * Retains the contexts in the supplied collection and the default context (if it's also not included in the + * supplied collection). + * + * @param aCollection A collection of URIs to retain, removing the rest + * @return Whether the URIs were successfully retained + */ + @Override + public boolean retainAll(final Collection aCollection) { + final boolean result = super.retainAll(aCollection); + + // If we haven't added retained the required context, we add it back + if (!PRESENTATION_CONTEXT_URI.equals(get(0))) { + super.add(0, PRESENTATION_CONTEXT_URI); + } + + return result; + } + + /** + * Sets the supplied context URI at the supplied index position. The default context can not be set with this + * method. + * + * @param aIndex An index position of the URI to set + * @param aURI A URI to set at the supplied index position + * @return The context URI that used to be at the supplied index position + */ + @Override + public URI set(final int aIndex, final URI aURI) { + if (PRESENTATION_CONTEXT_URI.equals(aURI)) { + if (aIndex != 0) { + throw new IndexOutOfBoundsException(LOGGER.getMessage(MessageCodes.JPA_149)); + } // else, just ignore -- this should be the current index of the default context + } else if (aIndex != 0) { + return super.set(aIndex, aURI); + } + + throw new IndexOutOfBoundsException(LOGGER.getMessage(MessageCodes.JPA_151, aURI)); + } + + /** + * This method is not supported because {@code ContextList} has a prescribed sort order that can not be overridden. + * + * @param aComparator A comparator that could be used to sort the list + */ + @Override + public void sort(final Comparator aComparator) { + throw new UnsupportedOperationException(); + } + + /** + * A context list comparator that makes sure the required context is always last in the list. + *

+ * Cf. https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions + *

+ */ + private static final class ContextListComparator implements Comparator { + + @Override + public int compare(final URI aFirstURI, final URI aSecondURI) { + int result = 0; + + if (!PRESENTATION_CONTEXT_URI.equals(aFirstURI) || !PRESENTATION_CONTEXT_URI.equals(aSecondURI)) { + if (PRESENTATION_CONTEXT_URI.equals(aFirstURI)) { + result = -1; + } else if (PRESENTATION_CONTEXT_URI.equals(aSecondURI)) { + result = 1; + } + } + + return result; + } + + } +} diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Manifest.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Manifest.java index 2df3832e..d9a31167 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Manifest.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Manifest.java @@ -1,7 +1,6 @@ package info.freelibrary.iiif.presentation.v3; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -70,6 +69,7 @@ public class Manifest extends NavigableResource implements Resource getCanvases() { return myCanvases; } - /** - * Gets the primary manifest context. - * - * @return The manifest context - */ - @Override - @JsonIgnore - public URI getContext() { - return PRESENTATION_CONTEXT_URI; - } - /** * Gets the manifest's placeholder canvas. * diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/NavigableResource.java b/src/main/java/info/freelibrary/iiif/presentation/v3/NavigableResource.java index 7ffdb952..93619c3e 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/NavigableResource.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/NavigableResource.java @@ -1,24 +1,18 @@ package info.freelibrary.iiif.presentation.v3; -import static info.freelibrary.util.Constants.SINGLE_INSTANCE; - import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import info.freelibrary.util.Logger; -import info.freelibrary.util.LoggerFactory; import info.freelibrary.util.warnings.JDK; import info.freelibrary.iiif.presentation.v3.exts.geo.NavPlace; @@ -26,18 +20,19 @@ import info.freelibrary.iiif.presentation.v3.properties.Label; import info.freelibrary.iiif.presentation.v3.properties.NavDate; import info.freelibrary.iiif.presentation.v3.utils.JsonKeys; -import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; +import info.freelibrary.iiif.presentation.v3.utils.json.ContextListDeserializer; +import info.freelibrary.iiif.presentation.v3.utils.json.ContextListSerializer; /** * A navigable resource. */ class NavigableResource> extends AbstractResource { - /** The navigable resource's logger. */ - private static final Logger LOGGER = LoggerFactory.getLogger(Manifest.class, MessageCodes.BUNDLE); - - /** The manifest's contexts. */ - private final List myContexts = Stream.of(PRESENTATION_CONTEXT_URI).collect(Collectors.toList()); + /** The resource's contexts. */ + @JsonProperty(JsonKeys.CONTEXT) + @JsonSerialize(using = ContextListSerializer.class) + @JsonDeserialize(using = ContextListDeserializer.class) + private ContextList myContexts; /** The date of the navigable resource. */ private NavDate myNavDate; @@ -79,41 +74,6 @@ protected NavigableResource(final String aType, final String aID, final Label aL super(aType, aID, aLabel, aBehaviorClass); } - /** - * Adds an array of new context URIs to the navigable resource. - * - * @param aContextArray Context URIs(s) - * @return The navigable resource - */ - @SuppressWarnings({ JDK.UNCHECKED }) - public T addContexts(final URI... aContextArray) { - Objects.requireNonNull(aContextArray, MessageCodes.JPA_007); - - for (final URI uri : aContextArray) { - Objects.requireNonNull(uri, MessageCodes.JPA_007); - - if (!PRESENTATION_CONTEXT_URI.equals(uri)) { - myContexts.add(uri); - } - } - - Collections.sort(myContexts, new ContextListComparator<>()); - return (T) this; - } - - /** - * Clears all contexts, but the required one. - * - * @return The navigable resource - */ - @SuppressWarnings({ JDK.UNCHECKED }) - public T clearContexts() { - myContexts.clear(); - myContexts.add(PRESENTATION_CONTEXT_URI); - - return (T) this; - } - @Override @SuppressWarnings(JDK.UNCHECKED) public boolean equals(final Object aObject) { @@ -134,28 +94,13 @@ public boolean equals(final Object aObject) { } /** - * Gets the primary context. - * - * @return The primary context - */ - @JsonIgnore - public URI getContext() { - return PRESENTATION_CONTEXT_URI; - } - - /** - * Gets an unmodifiable list of contexts. To remove contexts, use {@link #removeContext(URI) removeContext} or - * {@link #clearContexts() clearContexts}. + * Gets the resource's contexts. * - * @return The context + * @return The contexts */ @JsonIgnore public List getContexts() { - if (myContexts.isEmpty()) { - return Collections.emptyList(); - } - - return Collections.unmodifiableList(myContexts); + return getContextList(); } /** @@ -184,26 +129,28 @@ public int hashCode() { } /** - * Remove the supplied context. This will not remove the default required context though. If that's supplied, an - * {@link UnsupportedOperationException} will be thrown. + * Sets the manifest's contexts from a list that Jackson builds. * - * @param aContextURI A context to be removed from the contexts list - * @return True if the context was removed; else, false - * @throws UnsupportedOperationException If the required context is supplied to be removed + * @param aContextList A list of contexts + * @return This resource */ - public boolean removeContext(final URI aContextURI) { - if (PRESENTATION_CONTEXT_URI.equals(aContextURI)) { - throw new UnsupportedOperationException(LOGGER.getMessage(MessageCodes.JPA_039, PRESENTATION_CONTEXT_URI)); + @JsonIgnore + @SuppressWarnings({ JDK.UNCHECKED }) + public T setContexts(final List aContextList) { + if (aContextList instanceof final ContextList contextList) { + myContexts = contextList; + } else { + myContexts = new ContextList(aContextList); } - return myContexts.remove(aContextURI); + return (T) this; } /** * Sets a navigation date. * * @param aNavDate The navigation date - * @return The navigable resource + * @return This resource */ @JsonSetter(JsonKeys.NAV_DATE) @SuppressWarnings({ JDK.UNCHECKED }) @@ -216,7 +163,7 @@ public T setNavDate(final NavDate aNavDate) { * Sets the navigation place. * * @param aNavPlace The navigation place - * @return The navigable resource + * @return This resource */ @JsonSetter(JsonKeys.NAV_PLACE) @SuppressWarnings({ JDK.UNCHECKED }) @@ -226,111 +173,16 @@ public T setNavPlace(final NavPlace aNavPlace) { } /** - * Method used internally to set context from JSON. - * - * @param aObject A Jackson deserialization object - */ - @JsonSetter(JsonKeys.CONTEXT) - protected void deserializeContexts(final Object aObject) { - if (aObject instanceof final String context) { - deserializeContexts(List.of(context)); - } else if (aObject instanceof final List genericList) { - validateAndSetContexts(genericList); - } else { - throw new IllegalArgumentException(LOGGER.getMessage(MessageCodes.JPA_113)); - } - } - - /** - * Gets the manifest context. The manifest can either have a single context or an array of contexts (Cf. - * https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions) + * Gets the resource's contexts. * - * @return The manifest context - */ - @JsonGetter(JsonKeys.CONTEXT) - protected Object getJsonContext() { - if (myContexts.size() == SINGLE_INSTANCE) { - return myContexts.get(0); - } - - if (!myContexts.isEmpty()) { - return myContexts; - } - - return null; - } - - /** - * Sets the manifest's contexts from a list that Jackson builds. - * - * @param aContextList A list of contexts + * @return The contexts */ @JsonIgnore - private void setContexts(final List aContextList) { - final List indices = new ArrayList<>(); - final List contextList = new ArrayList<>(); - - for (int index = 0; index < aContextList.size(); index++) { - final URI context = URI.create((String) aContextList.get(index)); - - if (PRESENTATION_CONTEXT_URI.equals(context)) { - indices.add(index); // We may have more than one required context in supplied list - - if (indices.size() == SINGLE_INSTANCE) { // Only keep one if this is the case - contextList.add(context); - } - } else { - contextList.add(context); - } - } - - // Remove required context; we'll add it back at the end - if (!indices.isEmpty()) { - contextList.remove((int) indices.get(0)); - } - - myContexts.clear(); - myContexts.addAll(contextList); - myContexts.add(PRESENTATION_CONTEXT_URI); // Add required context at end - } - - /** - * Sets the contexts after confirming their validity. - * - * @param aContextList A list of contexts - * @throws IllegalArgumentException if a supplied context isn't a string - */ - @SuppressWarnings({ JDK.UNCHECKED }) - private void validateAndSetContexts(final List aContextList) { - if (aContextList.isEmpty() || aContextList.stream().anyMatch(item -> !(item instanceof String))) { - throw new IllegalArgumentException(LOGGER.getMessage(MessageCodes.JPA_113)); - } - - setContexts(aContextList); - } - - /** - * A context list comparator that makes sure the required context is always last in the list. - *

- * Cf. https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions - *

- */ - static class ContextListComparator implements Comparator { - - @Override - public int compare(final U aFirstURI, final U aSecondURI) { - int result = 0; - - if (!PRESENTATION_CONTEXT_URI.equals(aFirstURI) || !PRESENTATION_CONTEXT_URI.equals(aSecondURI)) { - if (PRESENTATION_CONTEXT_URI.equals(aFirstURI)) { - result = 1; - } else if (PRESENTATION_CONTEXT_URI.equals(aSecondURI)) { - result = -1; - } - } - - return result; + protected final List getContextList() { + if (myContexts == null) { + myContexts = new ContextList(); } + return myContexts; } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java index b8ff6065..ba6690a5 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java @@ -201,9 +201,4 @@ public final PlaceholderCanvas supplementWith(final String aCanvasRegion, final List aContentList) { return super.supplement(this, new MediaFragmentSelector(aCanvasRegion), false, aContentList); } - - @Override - protected Object getJsonContext() { - return null; - } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/Range.java b/src/main/java/info/freelibrary/iiif/presentation/v3/Range.java index c6508c5e..1a647ffb 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/Range.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/Range.java @@ -295,19 +295,6 @@ public Range setViewingDirection(final ViewingDirection aViewingDirection) { return this; } - /** - * Gets the manifest context. The manifest can either have a single context or an array of contexts (Cf. - * https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions) - * - * @return The manifest context - */ - @Override - @JsonGetter(JsonKeys.CONTEXT) - @JsonInclude(Include.NON_NULL) - protected Object getJsonContext() { - return null; - } - /** * A wrapper for the types of resources that can be put into a range's items: {@link Canvas}, {@link Range}, and * {@link SpecificResource}. diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/RangeCanvas.java b/src/main/java/info/freelibrary/iiif/presentation/v3/RangeCanvas.java index a28416c7..98d791ca 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/RangeCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/RangeCanvas.java @@ -74,16 +74,6 @@ class RangeCanvas extends Canvas { mySourceCanvas = aCanvas; } - @Override - public Canvas addContexts(final URI... aContextArray) { - return mySourceCanvas.addContexts(aContextArray); - } - - @Override - public Canvas clearContexts() { - return mySourceCanvas.clearContexts(); - } - @Override public boolean equals(final Object aObject) { return mySourceCanvas.equals(aObject); @@ -99,11 +89,6 @@ public List getBehaviors() { return mySourceCanvas.getBehaviors(); } - @Override - public URI getContext() { - return mySourceCanvas.getContext(); - } - @Override public List getContexts() { return mySourceCanvas.getContexts(); @@ -149,11 +134,6 @@ public Optional getNavPlace() { return mySourceCanvas.getNavPlace(); } - @Override - public List> getWebAnnotations() { - return mySourceCanvas.getWebAnnotations(); - } - @Override @JsonGetter(JsonKeys.ITEMS) @JsonInclude(Include.NON_EMPTY) // This serialization method is why this wrapper class was created @@ -221,6 +201,11 @@ public String getType() { return mySourceCanvas.getType(); } + @Override + public List> getWebAnnotations() { + return mySourceCanvas.getWebAnnotations(); + } + @Override public int getWidth() { return mySourceCanvas.getWidth(); @@ -231,11 +216,6 @@ public int hashCode() { return mySourceCanvas.hashCode(); } - @Override - public boolean removeContext(final URI aContextURI) { - return mySourceCanvas.removeContext(aContextURI); - } - @Override public Canvas setAccompanyingCanvas(final AccompanyingCanvas aCanvas) { return mySourceCanvas.setAccompanyingCanvas(aCanvas); @@ -381,11 +361,6 @@ protected float convertToFinitePositiveFloat(final Number aNumber) { return mySourceCanvas.convertToFinitePositiveFloat(aNumber); } - @Override - protected Object getJsonContext() { - return mySourceCanvas.getJsonContext(); - } - @Override boolean canFrame(final ContentResource aContent) { return mySourceCanvas.canFrame(aContent); diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java new file mode 100644 index 00000000..6409759b --- /dev/null +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java @@ -0,0 +1,66 @@ + +package info.freelibrary.iiif.presentation.v3.utils.json; + +import static info.freelibrary.iiif.presentation.v3.ContextList.PRESENTATION_CONTEXT_URI; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import info.freelibrary.iiif.presentation.v3.ContextList; + +/** + * A custom deserializer for ContextList. Deserialization is a little different because it either deserializes from a + * single string or a list of strings, depending on list size. + */ +public class ContextListDeserializer extends StdDeserializer> { + + /** The {@code ContextListDeserializer}'s {@code serialVersionUID}. */ + private static final long serialVersionUID = 3623670131870204191L; + + /** + * Creates a new {@link ContextList} deserializer. + */ + protected ContextListDeserializer() { + this(null); + } + + /** + * Creates a new {@link ContextList} deserializer. + * + * @param aClass The class to deserialize + */ + protected ContextListDeserializer(final Class aClass) { + super(aClass); + } + + @Override + public List deserialize(final JsonParser aParser, final DeserializationContext aContext) + throws IOException, JacksonException { + final JsonNode currentNode = aParser.getCodec().readTree(aParser); + final ContextList contexts = new ContextList(); + + if (currentNode.isArray()) { + currentNode.forEach(uri -> { + if (!PRESENTATION_CONTEXT_URI.toString().equals(uri)) { + contexts.add(URI.create(uri.textValue())); + } + }); + } else { + final String uri = currentNode.textValue(); + + if (!PRESENTATION_CONTEXT_URI.toString().equals(uri)) { + contexts.add(URI.create(uri)); + } + } + + return contexts; + } + +} diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java new file mode 100644 index 00000000..eb2c6252 --- /dev/null +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java @@ -0,0 +1,58 @@ + +package info.freelibrary.iiif.presentation.v3.utils.json; + +import static info.freelibrary.util.Constants.SINGLE_INSTANCE; + +import java.io.IOException; +import java.net.URI; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import info.freelibrary.util.ThrowingConsumer; + +import info.freelibrary.iiif.presentation.v3.ContextList; + +/** + * A custom serializer for ContextList. Serialization is a little different because it either serializes as a single + * string or a list of strings, depending on list size. + */ +public class ContextListSerializer extends StdSerializer { + + /** The {@code ContextListSerializer}'s {@code serialVersionUID}. */ + private static final long serialVersionUID = 7538668057735707536L; + + /** + * Creates a new {@code ContextListSerializer}. + */ + public ContextListSerializer() { + super(ContextList.class, true); + } + + /** + * Creates a new {@code ContextListSerializer} from the supplied class. + * + * @param aClass The class to serialize + */ + public ContextListSerializer(final Class aClass) { + super(aClass, true); + } + + @Override + public void serialize(final ContextList aContextList, final JsonGenerator aJsonGenerator, + final SerializerProvider aProvider) throws IOException { + if (aContextList.size() == SINGLE_INSTANCE) { + aJsonGenerator.writeString(aContextList.get(0).toString()); + } else { + aJsonGenerator.writeStartArray(); + + aContextList.stream().map(URI::toString).forEach((ThrowingConsumer) uri -> { + aJsonGenerator.writeString(uri); + }); + + aJsonGenerator.writeEndArray(); + } + } + +} diff --git a/src/main/resources/iiif_presentation_messages.xml b/src/main/resources/iiif_presentation_messages.xml index 2c9d5f30..68fbc439 100644 --- a/src/main/resources/iiif_presentation_messages.xml +++ b/src/main/resources/iiif_presentation_messages.xml @@ -119,4 +119,8 @@ {} is not a valid navPlace type A physical dimensions service must contain scale and units Supplied Optional was unexpectedly empty + The IIIF Presentation context URI can only exist as the first context in the list + Context '{}' was added at list position 1 because 0 is reserved for the default context + The '{}' context cannot be set as the first context; this position is reserved for the default + IIIF Presentation context diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java index b1eae6a9..06aa87f2 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/AbstractCanvasTest.java @@ -133,30 +133,6 @@ public final void testSetMinter() { assertTrue(new TestClass(id).setMinter(minter).getMinter().isPresent()); } - /** - * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. - */ - @Test - public final void testSetWebAnnotations() { - final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); - final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); - - page.addAnnotations(new BookmarkingAnnotation(minter)); - assertEquals(1, new TestClass(minter).setWebAnnotations(page).getWebAnnotations().size()); - } - - /** - * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. - */ - @Test - public final void testSetWebAnnotationsList() { - final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); - final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); - - page.addAnnotations(new BookmarkingAnnotation(minter)); - assertEquals(1, new TestClass(minter).setWebAnnotations(List.of(page)).getWebAnnotations().size()); - } - /** * Tests {@link AbstractCanvas#setPaintingPages()}. */ @@ -204,6 +180,30 @@ public final void testSetSupplementingPagesList() { .getSupplementingPages().size()); } + /** + * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. + */ + @Test + public final void testSetWebAnnotations() { + final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); + final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); + + page.addAnnotations(new BookmarkingAnnotation(minter)); + assertEquals(1, new TestClass(minter).setWebAnnotations(page).getWebAnnotations().size()); + } + + /** + * Tests {@link AbstractCanvas#setWebAnnotations(AnnotationPage)}. + */ + @Test + public final void testSetWebAnnotationsList() { + final Minter minter = MinterFactory.getMinter(HTTPS + UUID.randomUUID().toString()); + final AnnotationPage page = new AnnotationPage<>(minter, new Canvas(minter)); + + page.addAnnotations(new BookmarkingAnnotation(minter)); + assertEquals(1, new TestClass(minter).setWebAnnotations(List.of(page)).getWebAnnotations().size()); + } + /** * A test class. */ @@ -226,11 +226,6 @@ private TestClass(final Minter aMinter) { private TestClass(final String aID) { super(aID); } - - @Override - protected Object getJsonContext() { - return null; - } } } diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java index 5876dc8a..d05f3b27 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/CollectionTest.java @@ -216,14 +216,6 @@ public void testGetCollectionNotNull() { assertEquals(0, new Collection(myID, myLabel).getItems().size()); } - /** - * Tests {@link Collection#getContext()}. - */ - @Test - public void testGetContext() { - assertEquals(Collection.PRESENTATION_CONTEXT_URI, new Collection(myID, myLabel).getContext()); - } - /** * Tests setting a navDate. */ diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java new file mode 100644 index 00000000..c8f06293 --- /dev/null +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java @@ -0,0 +1,283 @@ + +package info.freelibrary.iiif.presentation.v3; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import org.junit.Test; + +/** + * Tests of {@link ContextList}. + */ +public class ContextListTest extends AbstractTest { + + /** A list of test contexts. */ + private final List myContexts = Arrays.asList(URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), + URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), + URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), + ContextList.PRESENTATION_CONTEXT_URI); + + /** + * Test method for {@link ContextList#addAll(Collection)}. + */ + @Test + public final void testAddAllCollectionOfQextendsURI() { + final ContextList contexts = new ContextList(); + + assertEquals(1, contexts.size()); + contexts.addAll(myContexts); + assertEquals(12, contexts.size()); + } + + /** + * Test method for {@link ContextList#addAll(int, Collection)}. + */ + @Test + public final void testAddAllIntCollectionOfQextendsURI() { + final ContextList contexts = new ContextList(myContexts); + final URI newURI1 = URI.create(getURL()); + final URI newURI2 = URI.create(getURL()); + final URI oldURI = contexts.get(8); + + assertEquals(12, contexts.size()); + assertEquals(oldURI, contexts.get(8)); + contexts.addAll(8, List.of(newURI1, newURI2)); + assertEquals(14, contexts.size()); + assertEquals(newURI1, contexts.get(8)); + } + + /** + * Test method for {@link ContextList#addFirst(URI)}. + */ + @Test + public final void testAddFirstURI() { + final ContextList contexts = new ContextList(); + final URI uri = URI.create(getURL()); + + assertEquals(1, contexts.size()); + contexts.addFirst(uri); + assertEquals(2, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + assertEquals(uri, contexts.get(1)); + } + + /** + * Test method for {@link ContextList#add(int, URI)}. + */ + @Test + public final void testAddIntURI() { + final ContextList contexts = new ContextList(); + final URI uri = URI.create(getURL()); + + assertEquals(1, contexts.size()); + contexts.add(0, uri); + assertEquals(2, contexts.size()); + assertEquals(uri, contexts.get(1)); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#addLast(URI)}. + */ + @Test + public final void testAddLastURI() { + final ContextList contexts = new ContextList(); + final URI uri = URI.create(getURL()); + + assertEquals(1, contexts.size()); + contexts.addLast(uri); + assertEquals(2, contexts.size()); + assertEquals(uri, contexts.get(1)); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#add(URI)}. + */ + @Test + public final void testAddURI() { + final ContextList contexts = new ContextList(); + final URI uri = URI.create(getURL()); + + assertEquals(1, contexts.size()); + contexts.add(uri); + assertEquals(2, contexts.size()); + assertEquals(uri, contexts.get(1)); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#clear()}. + */ + @Test + public final void testClear() { + final ContextList contexts = new ContextList(myContexts); + + assertEquals(12, contexts.size()); + contexts.clear(); + assertEquals(1, contexts.size()); + } + + /** + * Test method for {@link ContextList#ContextList()}. + */ + @Test + public final void testContextList() { + final ContextList contexts = new ContextList(); + + assertEquals(1, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#ContextList(List)}. + */ + @Test + public final void testContextListListOfURI() { + final ContextList contexts = new ContextList(myContexts); + + assertEquals(12, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#equals(Object)}. + */ + @Test + public final void testEqualsObject() { + final ContextList contexts1 = new ContextList(myContexts); + final ContextList contexts2 = new ContextList(myContexts); + + assertEquals(contexts1, contexts2); + } + + /** + * Test method for {@link ContextList#hashCode()}. + */ + @Test + public final void testHashCode() { + final ContextList contexts1 = new ContextList(myContexts); + final ContextList contexts2 = new ContextList(myContexts); + + assertEquals(contexts1.hashCode(), contexts2.hashCode()); + } + + /** + * Test method for {@link ContextList#removeAll(Collection)}. + */ + @Test + public final void testRemoveAllCollectionOfQ() { + final ContextList contexts = new ContextList(myContexts); + final URI uri1 = contexts.get(5); + final URI uri2 = contexts.get(8); + final URI uri3 = contexts.get(11); + final List list = List.of(uri1, uri2, uri3); + + assertEquals(12, contexts.size()); + contexts.removeAll(list); + assertEquals(9, contexts.size()); + } + + /** + * Test method for {@link ContextList#removeIf(Predicate)}. + */ + @Test + public final void testRemoveIfPredicateOfQsuperURI() { + // fail("Not yet implemented"); + } + + /** + * Test method for {@link ContextList#remove(int)}. + */ + @Test + public final void testRemoveInt() { + final ContextList contexts = new ContextList(myContexts); + final URI uri = contexts.get(8); + + assertEquals(12, contexts.size()); + assertTrue(contexts.contains(uri)); + contexts.remove(8); + assertEquals(11, contexts.size()); + assertFalse(contexts.contains(uri)); + } + + /** + * Test method for {@link ContextList#removeLast()}. + */ + @Test + public final void testRemoveLast() { + final ContextList contexts = new ContextList(myContexts); + final URI uri = contexts.get(contexts.size() - 1); + + assertTrue(contexts.contains(uri)); + contexts.removeLast(); + assertFalse(contexts.contains(uri)); + } + + /** + * Test method for {@link ContextList#remove(Object)}. + */ + @Test + public final void testRemoveObject() { + final ContextList contexts = new ContextList(myContexts); + final URI uri = contexts.get(8); + + assertTrue(contexts.contains(uri)); + contexts.remove(uri); + assertFalse(contexts.contains(uri)); + } + + /** + * Test method for {@link ContextList#replaceAll(UnaryOperator)}. + */ + @Test + public final void testReplaceAllUnaryOperatorOfURI() { + // fail("Not yet implemented"); + } + + /** + * Test method for {@link ContextList#retainAll(Collection)}. + */ + @Test + public final void testRetainAllCollectionOfQ() { + final ContextList contexts = new ContextList(myContexts); + final URI uri1 = contexts.get(5); + final URI uri2 = contexts.get(8); + + assertEquals(12, contexts.size()); + contexts.retainAll(List.of(uri1, uri2)); + assertEquals(3, contexts.size()); + } + + /** + * Test method for {@link ContextList#set(int, URI)}. + */ + @Test + public final void testSetIntURI() { + final ContextList contexts = new ContextList(myContexts); + final URI uri = URI.create(getURL()); + + assertNotEquals(uri, contexts.get(1)); + contexts.set(1, uri); + assertEquals(uri, contexts.get(1)); + } + + /** + * Test method for {@link ContextList#sort(Comparator)}. + */ + @Test(expected = UnsupportedOperationException.class) + public final void testSortComparatorOfQsuperURI() { + new ContextList(myContexts).sort((aUriOne, aUriTwo) -> 0); + } + +} diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java index 6ea6bc34..8bc2ee40 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ManifestTest.java @@ -10,10 +10,8 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.stream.Stream; @@ -86,12 +84,6 @@ public class ManifestTest extends AbstractTest { /** A test width. */ private static final int WIDTH = 6132; - /** A list of test contexts. */ - private final List myContexts = Arrays.asList(URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), - URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), - URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), - AbstractResource.PRESENTATION_CONTEXT_URI); - /** The test manifest. */ private Manifest myManifest; @@ -203,53 +195,6 @@ public void testAddRangesList() { assertEquals(1, myManifest.getRanges().size()); } - /** - * Tests adding a context URI. - */ - @Test - public void testAddUriContexts() { - assertEquals(1, myManifest.getContexts().size()); - myManifest.addContexts(URI.create(myLoremIpsum.getUrl()), URI.create(myLoremIpsum.getUrl())); - assertEquals(3, myManifest.getContexts().size()); - } - - /** - * Tests clearing the contexts. - */ - @Test - public void testClearContexts() { - assertEquals(1, myManifest.getContexts().size()); - myManifest.addContexts(URI.create(myLoremIpsum.getUrl()), URI.create(myLoremIpsum.getUrl())); - assertEquals(3, myManifest.getContexts().size()); - assertEquals(1, myManifest.clearContexts().getContexts().size()); - } - - /** - * Tests the comparator's sort. - */ - @Test - public final void testComparatorSort() { - final int lastIndex = myContexts.size() - 1; - final List preSort = new ArrayList<>(); - - // Shuffle until our last list item isn't the required one - while (AbstractResource.PRESENTATION_CONTEXT_URI.equals(myContexts.get(lastIndex))) { - Collections.shuffle(myContexts); - } - - // Remember the state of our list before the sort, minus the required Context - assertTrue(preSort.addAll(myContexts)); - assertTrue(preSort.remove(AbstractResource.PRESENTATION_CONTEXT_URI)); - - // Sort list items - Collections.sort(myContexts, new NavigableResource.ContextListComparator<>()); - - // Check that the last URI in the list is our required one and - // that list has same pre-sort order minus the required context - assertEquals(AbstractResource.PRESENTATION_CONTEXT_URI, myContexts.get(lastIndex)); - assertEquals(preSort, myContexts.subList(0, lastIndex)); - } - /** * Tests the manifest constructor. */ @@ -261,15 +206,6 @@ public void testConstructorStringLabel() { assertEquals(METADATA_PAIRS.get(0)[1], myManifest.getLabel().get().getString()); } - /** - * Tests {@link Manifest#getContext() getContext} method. - */ - @Test - public void testGetPrimaryContext() { - assertEquals(AbstractResource.PRESENTATION_CONTEXT_URI, - myManifest.addContexts(URI.create(myLoremIpsum.getUrl())).getContext()); - } - /** * Tests {@link NavigableResource#equals(Object) NavigableResource}. */ @@ -355,27 +291,6 @@ public void testParsingManifest() throws IOException { assertEquals(expected, format(found)); } - /** - * Tests {@link Manifest#removeContext(URI) removeContext} method. - */ - @Test - public void testRemoveContext() { - final URI uri = URI.create("https://asdf.example.com"); - - myManifest.addContexts(uri, URI.create("https://fdsa.example.com")); - assertTrue(myManifest.getContexts().contains(uri)); - assertTrue(myManifest.removeContext(uri)); - assertEquals(2, myManifest.getContexts().size()); - } - - /** - * Tests getting an exception on trying to remove the required context. - */ - @Test(expected = UnsupportedOperationException.class) - public void testRemovePrimaryContext() { - myManifest.removeContext(AbstractResource.PRESENTATION_CONTEXT_URI); - } - /** * Tests setting annotations. */ From a7ba8ad57c6f0a177248cc103ab2931ede8996f9 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Mon, 2 Sep 2024 17:17:55 -0400 Subject: [PATCH 3/8] WIP --- .../iiif/presentation/v3/ContextList.java | 25 ++++++++++--------- .../utils/json/ContextListDeserializer.java | 18 ++++++------- .../v3/utils/json/ContextListSerializer.java | 7 +----- .../iiif/presentation/v3/ContextListTest.java | 15 +++++++++-- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java index 5506f7f4..e2a137f2 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java @@ -3,6 +3,7 @@ import static info.freelibrary.util.Constants.SINGLE_INSTANCE; +import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -12,12 +13,11 @@ import java.util.NoSuchElementException; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; -import java.util.stream.Stream; import info.freelibrary.util.Logger; import info.freelibrary.util.LoggerFactory; import info.freelibrary.util.warnings.PMD; +import info.freelibrary.util.warnings.Sonar; import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; @@ -36,7 +36,7 @@ public class ContextList extends ArrayList implements List { private static final long serialVersionUID = -877433424933939199L; /** A simple sorter that only moves the required context to the first slot. */ - private final Comparator myComparator; + private final ContextListComparator myComparator; /** * Creates a new list of contexts. It includes the IIIF Presentation context by default. @@ -136,7 +136,7 @@ public boolean addAll(final int aIndex, final Collection aUriColl * * @param aURI A context URI to add at the beginning of the list */ - @SuppressWarnings(PMD.MISSING_OVERRIDE) + @SuppressWarnings({ PMD.MISSING_OVERRIDE, Sonar.OVERRIDE_REQUIRED }) public void addFirst(final URI aURI) { if (!PRESENTATION_CONTEXT_URI.equals(aURI)) { super.add(1, aURI); @@ -149,7 +149,7 @@ public void addFirst(final URI aURI) { * * @param aURI A context URI to add at the end of the list */ - @SuppressWarnings(PMD.MISSING_OVERRIDE) + @SuppressWarnings({ PMD.MISSING_OVERRIDE, Sonar.OVERRIDE_REQUIRED }) public void addLast(final URI aURI) { if (!PRESENTATION_CONTEXT_URI.equals(aURI)) { super.add(aURI); // Adding, by default, adds as the last item @@ -227,10 +227,8 @@ public boolean remove(final Object aObj) { @Override public boolean removeAll(final Collection aCollection) { if (aCollection.contains(PRESENTATION_CONTEXT_URI)) { - final Stream stream = aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)); - final List removables = stream.collect(Collectors.toList()); - - return super.removeAll(removables); + final List list = aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList(); + return super.removeAll(list); } return super.removeAll(aCollection); @@ -243,7 +241,7 @@ public boolean removeAll(final Collection aCollection) { * @param aFilter A filter to use to remove URIs from the list * @return True if the URIs were removed */ - @SuppressWarnings(PMD.MISSING_OVERRIDE) + @SuppressWarnings({ PMD.MISSING_OVERRIDE, Sonar.OVERRIDE_REQUIRED }) public boolean removeIf(final Predicate aFilter) { final boolean result = super.removeIf(aFilter); @@ -262,7 +260,7 @@ public boolean removeIf(final Predicate aFilter) { * @return The context URI that was removed * @throws NoSuchElementException If the list only has the required IIIF Presentation context */ - @SuppressWarnings(PMD.MISSING_OVERRIDE) + @SuppressWarnings({ PMD.MISSING_OVERRIDE, Sonar.OVERRIDE_REQUIRED }) public URI removeLast() { if (size() == SINGLE_INSTANCE) { throw new NoSuchElementException(LOGGER.getMessage(MessageCodes.JPA_039, PRESENTATION_CONTEXT_URI)); @@ -345,7 +343,10 @@ public void sort(final Comparator aComparator) { * Cf. https://iiif.io/api/presentation/3.0/#46-linked-data-context-and-extensions *

*/ - private static final class ContextListComparator implements Comparator { + private static final class ContextListComparator implements Comparator, Serializable { + + /** The {@code serialVersionUID} for the {@code ContextListComparator}. */ + private static final long serialVersionUID = 5516185678973318858L; @Override public int compare(final URI aFirstURI, final URI aSecondURI) { diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java index 6409759b..3fce2cce 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListDeserializer.java @@ -7,7 +7,6 @@ import java.net.URI; import java.util.List; -import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; @@ -41,22 +40,23 @@ protected ContextListDeserializer(final Class aClass) { } @Override - public List deserialize(final JsonParser aParser, final DeserializationContext aContext) - throws IOException, JacksonException { + public List deserialize(final JsonParser aParser, final DeserializationContext aContext) throws IOException { final JsonNode currentNode = aParser.getCodec().readTree(aParser); final ContextList contexts = new ContextList(); if (currentNode.isArray()) { - currentNode.forEach(uri -> { - if (!PRESENTATION_CONTEXT_URI.toString().equals(uri)) { - contexts.add(URI.create(uri.textValue())); + currentNode.forEach(context -> { + final URI uri = URI.create(context.textValue()); + + if (!PRESENTATION_CONTEXT_URI.equals(uri)) { + contexts.add(uri); } }); } else { - final String uri = currentNode.textValue(); + final URI uri = URI.create(currentNode.textValue()); - if (!PRESENTATION_CONTEXT_URI.toString().equals(uri)) { - contexts.add(URI.create(uri)); + if (!PRESENTATION_CONTEXT_URI.equals(uri)) { + contexts.add(uri); } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java index eb2c6252..2f5c0e28 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/utils/json/ContextListSerializer.java @@ -46,13 +46,8 @@ public void serialize(final ContextList aContextList, final JsonGenerator aJsonG aJsonGenerator.writeString(aContextList.get(0).toString()); } else { aJsonGenerator.writeStartArray(); - - aContextList.stream().map(URI::toString).forEach((ThrowingConsumer) uri -> { - aJsonGenerator.writeString(uri); - }); - + aContextList.stream().map(URI::toString).forEach((ThrowingConsumer) aJsonGenerator::writeString); aJsonGenerator.writeEndArray(); } } - } diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java index c8f06293..055fe9bf 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java @@ -193,7 +193,12 @@ public final void testRemoveAllCollectionOfQ() { */ @Test public final void testRemoveIfPredicateOfQsuperURI() { - // fail("Not yet implemented"); + final ContextList contexts = new ContextList(myContexts); + final URI kept = contexts.get(2); + + contexts.removeIf(uri -> !uri.equals(kept)); + assertEquals(2, contexts.size()); + assertTrue(contexts.contains(kept)); } /** @@ -242,7 +247,13 @@ public final void testRemoveObject() { */ @Test public final void testReplaceAllUnaryOperatorOfURI() { - // fail("Not yet implemented"); + final ContextList contexts = new ContextList(myContexts); + final URI uri = contexts.get(10); + final UnaryOperator uOp = u -> URI.create(u.toString().replace(uri.toString(), getURL())); + + assertTrue(contexts.contains(uri)); + contexts.replaceAll(uOp); + assertFalse(contexts.contains(uri)); } /** From 4476057156c0ec189190d4a182a5f0708e0f8516 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Mon, 2 Sep 2024 17:42:02 -0400 Subject: [PATCH 4/8] Bump freelib-utils versions --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 047a4ff9..d27fbe78 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 2.17.2 2.17.2 1.5.1 - 5.0.4 + 5.0.5 1.18.1 3.3.0 2.4 From 8113bd4cc01bffc174082593831c636902f1fc78 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Mon, 2 Sep 2024 21:58:02 -0400 Subject: [PATCH 5/8] Add more NavigableResource tests --- .../v3/NavigableResourceTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/NavigableResourceTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/NavigableResourceTest.java index d7733e17..6453d402 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/NavigableResourceTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/NavigableResourceTest.java @@ -5,6 +5,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import org.junit.Test; @@ -92,6 +95,54 @@ public final void testNavigableResourceEqualsString() { assertNotEquals(new TestClass(HTTPS + UUID.randomUUID().toString()), EMPTY); } + /** + * Tests {@link NavigableResource#getContextList() NavigableResource}. + */ + @Test + public final void testNavigableResourceGetContextList() { + final String id = UUID.randomUUID().toString(); + final NavigableResource test = new TestClass(HTTPS + id); + + assertEquals(1, test.getContextList().size()); // Uninitialized + assertEquals(1, test.getContextList().size()); // Should now be initialized + } + + /** + * Tests {@link NavigableResource#getContexts() NavigableResource}. + */ + @Test + public final void testNavigableResourceGetContexts() { + final String id = UUID.randomUUID().toString(); + final NavigableResource test = new TestClass(HTTPS + id); + + assertEquals(1, test.getContexts().size()); + } + + /** + * Tests {@link NavigableResource#setContexts(List) NavigableResource}. + */ + @Test + public final void testNavigableResourceSetContextsWithContextList() { + final String id = UUID.randomUUID().toString(); + final NavigableResource test = new TestClass(HTTPS + id); + final ContextList contexts = new ContextList(); + + assertEquals(contexts, test.setContexts(contexts).getContexts()); + } + + /** + * Tests {@link NavigableResource#setContexts(List) NavigableResource}. + */ + @Test + public final void testNavigableResourceSetContextsWithURIList() { + final String id = UUID.randomUUID().toString(); + final NavigableResource test = new TestClass(HTTPS + id); + final List contexts = new ArrayList<>(); + + contexts.add(URI.create(id)); + assertEquals(2, test.setContexts(contexts).getContexts().size()); + } + /** * A test class. */ From f9bbebbc228a14ea73a0c48d66c600921738fdca Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Tue, 3 Sep 2024 00:13:02 -0400 Subject: [PATCH 6/8] Add more ContextList tests --- .../iiif/presentation/v3/ContextList.java | 19 +-- .../iiif/presentation/v3/ContextListTest.java | 145 ++++++++++++++++++ 2 files changed, 151 insertions(+), 13 deletions(-) diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java index e2a137f2..dfbb12ac 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java @@ -118,16 +118,14 @@ public boolean addAll(final Collection aUriCollection) { * context list. * * @param aIndex An index position at which to add the URIs in the supplied collection - * @param aUriCollection A collection of URIs to add at the supplied index position + * @param aCollection A collection of URIs to add at the supplied index position * @return If all the supplied URIs were successfully added */ @Override - public boolean addAll(final int aIndex, final Collection aUriCollection) { - if (aUriCollection.contains(PRESENTATION_CONTEXT_URI)) { - aUriCollection.remove(PRESENTATION_CONTEXT_URI); - } - - return super.addAll(aIndex, aUriCollection); + public boolean addAll(final int aIndex, final Collection aCollection) { + final List uris = + aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList(); + return super.addAll(aIndex, uris); } /** @@ -226,12 +224,7 @@ public boolean remove(final Object aObj) { */ @Override public boolean removeAll(final Collection aCollection) { - if (aCollection.contains(PRESENTATION_CONTEXT_URI)) { - final List list = aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList(); - return super.removeAll(list); - } - - return super.removeAll(aCollection); + return super.removeAll(aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java index 055fe9bf..afe67dfc 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java @@ -6,7 +6,12 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; @@ -16,11 +21,19 @@ import org.junit.Test; +import info.freelibrary.util.Logger; +import info.freelibrary.util.LoggerFactory; + +import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; + /** * Tests of {@link ContextList}. */ public class ContextListTest extends AbstractTest { + /** A test logger. */ + private static final Logger LOGGER = LoggerFactory.getLogger(ContextListTest.class, MessageCodes.BUNDLE); + /** A list of test contexts. */ private final List myContexts = Arrays.asList(URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), URI.create(getURL()), @@ -39,6 +52,32 @@ public final void testAddAllCollectionOfQextendsURI() { assertEquals(12, contexts.size()); } + /** + * Test method for {@link ContextList#addAll(int, Collection)}. + */ + @Test + public final void testAddAllCollectionWithDefaultURI() { + final ContextList contexts = new ContextList(); + final ContextList adds = new ContextList(); + + assertEquals(1, contexts.size()); + contexts.addAll(0, adds); + assertEquals(1, contexts.size()); + } + + /** + * Test method for {@link ContextList#addAll(int, Collection)}. + */ + @Test + public final void testAddAllCollectionWithoutDefaultURI() { + final ContextList contexts = new ContextList(); + final List list = new ArrayList<>(List.of(URI.create(getURL()), URI.create(getURL()))); + + assertEquals(1, contexts.size()); + contexts.addAll(0, list); + assertEquals(3, contexts.size()); + } + /** * Test method for {@link ContextList#addAll(int, Collection)}. */ @@ -56,6 +95,30 @@ public final void testAddAllIntCollectionOfQextendsURI() { assertEquals(newURI1, contexts.get(8)); } + /** + * Test method for {@link ContextList#add(URI)}. + */ + @Test + public final void testAddFalse() { + final ContextList contexts = new ContextList(); + + assertEquals(1, contexts.size()); + assertFalse(contexts.add(ContextList.PRESENTATION_CONTEXT_URI)); + } + + /** + * Test method for {@link ContextList#addFirst(URI)}. + */ + @Test + public final void testAddFirstDefaultURI() { + final ContextList contexts = new ContextList(); + + assertEquals(1, contexts.size()); + contexts.addFirst(ContextList.PRESENTATION_CONTEXT_URI); + assertEquals(1, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + /** * Test method for {@link ContextList#addFirst(URI)}. */ @@ -79,6 +142,21 @@ public final void testAddIntURI() { final ContextList contexts = new ContextList(); final URI uri = URI.create(getURL()); + assertEquals(1, contexts.size()); + contexts.add(1, uri); + assertEquals(2, contexts.size()); + assertEquals(uri, contexts.get(1)); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + + /** + * Test method for {@link ContextList#add(int, URI)}. + */ + @Test + public final void testAddIntUriZeroIndex() { + final ContextList contexts = new ContextList(); + final URI uri = URI.create(getURL()); + assertEquals(1, contexts.size()); contexts.add(0, uri); assertEquals(2, contexts.size()); @@ -86,6 +164,28 @@ public final void testAddIntURI() { assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); } + /** + * Test method for {@link ContextList#addLast(URI)}. + */ + @Test + public final void testAddLastDefaultURI() throws IOException { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final PrintStream current = new PrintStream(out, true, StandardCharsets.UTF_8); + final PrintStream previous = System.out; + final ContextList contexts = new ContextList(); + + System.setOut(current); + + assertEquals(1, contexts.size()); + contexts.addLast(ContextList.PRESENTATION_CONTEXT_URI); + assertEquals(1, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + + System.setOut(previous); + + assertTrue(out.toString().contains(LOGGER.getMessage(MessageCodes.JPA_149))); + } + /** * Test method for {@link ContextList#addLast(URI)}. */ @@ -101,6 +201,19 @@ public final void testAddLastURI() { assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); } + /** + * Test method for {@link ContextList#add(int, URI)}. + */ + @Test + public final void testAddPresURI() { + final ContextList contexts = new ContextList(); + + assertEquals(1, contexts.size()); + contexts.add(0, ContextList.PRESENTATION_CONTEXT_URI); + assertEquals(1, contexts.size()); + assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); + } + /** * Test method for {@link ContextList#add(URI)}. */ @@ -150,6 +263,14 @@ public final void testContextListListOfURI() { assertEquals(ContextList.PRESENTATION_CONTEXT_URI, contexts.get(0)); } + /** + * Test method for {@link ContextList#equals(Object)}. + */ + @Test + public final void testEqualsNull() { + assertNotEquals(new ContextList(myContexts), null); + } + /** * Test method for {@link ContextList#equals(Object)}. */ @@ -161,6 +282,14 @@ public final void testEqualsObject() { assertEquals(contexts1, contexts2); } + /** + * Test method for {@link ContextList#equals(Object)}. + */ + @Test + public final void testEqualsString() { + assertNotEquals(new ContextList(myContexts), "asdf"); + } + /** * Test method for {@link ContextList#hashCode()}. */ @@ -188,6 +317,14 @@ public final void testRemoveAllCollectionOfQ() { assertEquals(9, contexts.size()); } + /** + * Test method for {@link ContextList#remove(Object)}. + */ + @Test + public final void testRemoveDefContextObject() { + new ContextList().remove(ContextList.PRESENTATION_CONTEXT_URI); + } + /** * Test method for {@link ContextList#removeIf(Predicate)}. */ @@ -242,6 +379,14 @@ public final void testRemoveObject() { assertFalse(contexts.contains(uri)); } + /** + * Test method for {@link ContextList#remove(int)}. + */ + @Test(expected = IndexOutOfBoundsException.class) + public final void testRemoveZeroIndex() { + new ContextList().remove(0); + } + /** * Test method for {@link ContextList#replaceAll(UnaryOperator)}. */ From 2f75222601f3e553a40099132a65df5f2c158915 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Tue, 3 Sep 2024 00:27:20 -0400 Subject: [PATCH 7/8] Resolve Sonar issues --- .../info/freelibrary/iiif/presentation/v3/ContextList.java | 6 +++--- .../freelibrary/iiif/presentation/v3/ContextListTest.java | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java index dfbb12ac..a57fd188 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java @@ -16,6 +16,7 @@ import info.freelibrary.util.Logger; import info.freelibrary.util.LoggerFactory; +import info.freelibrary.util.warnings.JDK; import info.freelibrary.util.warnings.PMD; import info.freelibrary.util.warnings.Sonar; @@ -122,10 +123,9 @@ public boolean addAll(final Collection aUriCollection) { * @return If all the supplied URIs were successfully added */ @Override + @SuppressWarnings(JDK.UNCHECKED) public boolean addAll(final int aIndex, final Collection aCollection) { - final List uris = - aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList(); - return super.addAll(aIndex, uris); + return super.addAll(aIndex, aCollection.stream().filter(uri -> !PRESENTATION_CONTEXT_URI.equals(uri)).toList()); } /** diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java index afe67dfc..ab858e7a 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.PrintStream; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -168,7 +167,7 @@ public final void testAddIntUriZeroIndex() { * Test method for {@link ContextList#addLast(URI)}. */ @Test - public final void testAddLastDefaultURI() throws IOException { + public final void testAddLastDefaultURI() { final ByteArrayOutputStream out = new ByteArrayOutputStream(); final PrintStream current = new PrintStream(out, true, StandardCharsets.UTF_8); final PrintStream previous = System.out; @@ -322,7 +321,7 @@ public final void testRemoveAllCollectionOfQ() { */ @Test public final void testRemoveDefContextObject() { - new ContextList().remove(ContextList.PRESENTATION_CONTEXT_URI); + assertFalse(new ContextList().remove(ContextList.PRESENTATION_CONTEXT_URI)); } /** From 991e70f83b2a6b6b8b5b1191e52ada93f733c600 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Tue, 3 Sep 2024 23:34:10 -0400 Subject: [PATCH 8/8] Add more ContextList tests --- .../iiif/presentation/v3/ContextList.java | 7 ++- .../iiif/presentation/v3/ContextListTest.java | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java index a57fd188..1d916bba 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ContextList.java @@ -312,8 +312,11 @@ public URI set(final int aIndex, final URI aURI) { if (PRESENTATION_CONTEXT_URI.equals(aURI)) { if (aIndex != 0) { throw new IndexOutOfBoundsException(LOGGER.getMessage(MessageCodes.JPA_149)); - } // else, just ignore -- this should be the current index of the default context - } else if (aIndex != 0) { + } + + return aURI; + } + if (aIndex != 0) { return super.set(aIndex, aURI); } diff --git a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java index ab858e7a..86770cbb 100644 --- a/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java +++ b/src/test/java/info/freelibrary/iiif/presentation/v3/ContextListTest.java @@ -1,6 +1,7 @@ package info.freelibrary.iiif.presentation.v3; +import static info.freelibrary.iiif.presentation.v3.ContextList.PRESENTATION_CONTEXT_URI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -15,6 +16,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.NoSuchElementException; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -337,6 +339,18 @@ public final void testRemoveIfPredicateOfQsuperURI() { assertTrue(contexts.contains(kept)); } + /** + * Test method for {@link ContextList#removeIf(Predicate)}. + */ + @Test + public final void testRemoveIfPredicateOfQsuperUriNoDefault() { + final ContextList contexts = new ContextList(myContexts); + + contexts.removeIf(uri -> !uri.equals(PRESENTATION_CONTEXT_URI)); + assertEquals(1, contexts.size()); + assertTrue(contexts.contains(PRESENTATION_CONTEXT_URI)); + } + /** * Test method for {@link ContextList#remove(int)}. */ @@ -365,6 +379,14 @@ public final void testRemoveLast() { assertFalse(contexts.contains(uri)); } + /** + * Test method for {@link ContextList#removeLast()}. + */ + @Test(expected = NoSuchElementException.class) + public final void testRemoveLastWhenEmpty() { + new ContextList().removeLast(); + } + /** * Test method for {@link ContextList#remove(Object)}. */ @@ -427,6 +449,30 @@ public final void testSetIntURI() { assertEquals(uri, contexts.get(1)); } + /** + * Test method for {@link ContextList#set(int, URI)}. + */ + @Test(expected = IndexOutOfBoundsException.class) + public final void testSetIntURIException() { + new ContextList(myContexts).set(1, PRESENTATION_CONTEXT_URI); + } + + /** + * Test method for {@link ContextList#set(int, URI)}. + */ + @Test(expected = IndexOutOfBoundsException.class) + public final void testSetIntURIException2() { + new ContextList(myContexts).set(0, URI.create(getURL())); + } + + /** + * Test method for {@link ContextList#set(int, URI)}. + */ + @Test + public final void testSetIntUriStatusQuo() { + new ContextList(myContexts).set(0, PRESENTATION_CONTEXT_URI); + } + /** * Test method for {@link ContextList#sort(Comparator)}. */