From 17ef7db427407d709ae60966e99f605ac01e7322 Mon Sep 17 00:00:00 2001 From: "Kevin S. Clarke" Date: Sun, 14 Apr 2024 00:16:02 -0400 Subject: [PATCH 01/40] [WIP] --- .../docs/recipes/code/0007-string-formats.md | 35 ++- .../presentation/v3/PlaceholderCanvas.java | 4 +- .../iiif/presentation/v3/ids/UriUtils.java | 2 +- .../iiif/presentation/v3/properties/I18n.java | 48 ++-- .../v3/properties/I18nProperty.java | 113 +++++---- .../presentation/v3/properties/Label.java | 227 +++++++++++++++--- .../presentation/v3/properties/Property.java | 26 +- .../presentation/v3/properties/Summary.java | 213 ++++++++++++++-- .../presentation/v3/properties/Value.java | 223 +++++++++++++++-- .../iiif/presentation/v3/utils/I18nUtils.java | 75 ++++-- .../resources/iiif_presentation_messages.xml | 4 + .../v3/examples/CookbooksTest.java | 78 ++++++ .../v3/properties/I18nPropertyTest.java | 151 +----------- 13 files changed, 882 insertions(+), 317 deletions(-) diff --git a/docs/content/en/docs/recipes/code/0007-string-formats.md b/docs/content/en/docs/recipes/code/0007-string-formats.md index 9b6ae104..77d24ad3 100644 --- a/docs/content/en/docs/recipes/code/0007-string-formats.md +++ b/docs/content/en/docs/recipes/code/0007-string-formats.md @@ -1,7 +1,32 @@ -+++ -title = "0007-string-formats" -weight = 0 -+++ +--- +title: "Embedding HTML in descriptive properties" +linkTitle: "0007-string-formats" +weight: 0 +--- -Content goes here! +You want to have more control on how your metadata is displayed by adding links or simple formatting instructions to selected text blocks. For example, scientific names +might need special formatting and links out to other sites benefit from being activatable. Legacy systems may also include rudimentary formatting in their output. +| | | +| :--- | :---: | +| Recipe: | https://iiif.io/api/cookbook/recipe/0007-string-formats/ | +| Manifest: | https://iiif.io/api/cookbook/recipe/0007-string-formats/manifest.json | + +### Method One + +For the first method, we use a Minter to create IDs for the components of the manifest. This allows us to use less code to create the same structures. It will, however, +create different IDs than are used in the cookbook recipe. + +```java + +``` + +### Method Two + +The second method will create a manifest with the same IDs that the cookbook recipe uses. It involves setting all the IDs manually, which involves a little more code. + +```java + +``` + +{{% sandbox %}} 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 9df01628..87c1b4d6 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/PlaceholderCanvas.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import info.freelibrary.util.warnings.Eclipse; +import info.freelibrary.util.warnings.PMD; import info.freelibrary.iiif.presentation.v3.annotations.WebAnnotation; import info.freelibrary.iiif.presentation.v3.ids.Minter; @@ -37,7 +38,8 @@ * resource. A placeholder canvas is likely to have different dimensions to those of the canvas(es) of the resource that * has the placeholderCanvas property. */ -@SuppressWarnings({ "PMD.TooManyMethods", "PMD.ExcessivePublicCount" }) +@SuppressWarnings({ PMD.TOO_MANY_METHODS, "PMD.TooManyMethods", PMD.EXCESSIVE_PUBLIC_COUNT, + "PMD.ExcessivePublicCount" }) public class PlaceholderCanvas extends AbstractCanvas implements Resource, CanvasResource { diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/ids/UriUtils.java b/src/main/java/info/freelibrary/iiif/presentation/v3/ids/UriUtils.java index 963cccf5..9439334b 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/ids/UriUtils.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/ids/UriUtils.java @@ -28,7 +28,7 @@ private UriUtils() { * @throws InvalidIdentifierException If the supplied identifier doesn't conform to IIIF's rules */ @SuppressWarnings({ "PMD.AvoidCatchingGenericException", PMD.AVOID_CATCHING_GENERIC_EXCEPTION, - "PMD.AvoidCatchingNPE" }) + "PMD.AvoidCatchingNPE", PMD.AVOID_CATCHING_NPE }) public static String checkID(final String aID, final boolean aHttpsReq) { final URI id; diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18n.java b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18n.java index b85cc38d..bcf2667a 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18n.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18n.java @@ -17,13 +17,10 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.core.JsonProcessingException; -import info.freelibrary.util.Logger; -import info.freelibrary.util.LoggerFactory; import info.freelibrary.util.warnings.PMD; import info.freelibrary.iiif.presentation.v3.utils.I18nUtils; import info.freelibrary.iiif.presentation.v3.utils.JSON; -import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; import info.freelibrary.iiif.presentation.v3.utils.json.JsonParsingException; /** @@ -38,11 +35,6 @@ public class I18n implements Iterable { */ public static final String DEFAULT_LANG = "none"; - /** - * The logger used by I18n. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(I18n.class, MessageCodes.BUNDLE); - /** * The standard types of immutable lists in Java; it doesn't include third party libraries like Guava. */ @@ -65,6 +57,25 @@ public class I18n implements Iterable { */ private Locale myLocale; + /** + * Creates an internationalization, using the default language tag, from the supplied string value. + * + * @param aString An internationalized value + */ + public I18n(final String aString) { + this(DEFAULT_LANG, aString); + } + + /** + * Creates an internationalization, using the default language tag, from the supplied string value. + * + * @param aString An internationalized value + * @param aHtmlAllowed Whether the supplied value can contain HTML + */ + public I18n(final String aString, final boolean aHtmlAllowed) { + this(DEFAULT_LANG, aString, aHtmlAllowed); + } + /** * Creates an internationalization from the supplied language tag and string value. * @@ -153,7 +164,7 @@ public I18n(final String aLangTag, final List aStringList, final boolean * in the list of strings after being disallowed */ public I18n(final Locale aLocale, final List aStringList, final boolean aHtmlValueAllowed) { - myLocale = checkLangTag(aLocale); + myLocale = I18nUtils.checkLocale(aLocale); isAllowingHTML = aHtmlValueAllowed; if (!isAllowingHTML) { @@ -194,7 +205,7 @@ public String getLang() { */ @JsonIgnore public I18n setLang(final String aLangTag) { - myLocale = checkLangTag(Locale.forLanguageTag(aLangTag)); + myLocale = I18nUtils.checkLocale(Locale.forLanguageTag(aLangTag)); return this; } @@ -207,7 +218,7 @@ public I18n setLang(final String aLangTag) { */ @JsonIgnore public I18n setLang(final Locale aLocale) { - myLocale = checkLangTag(aLocale); + myLocale = I18nUtils.checkLocale(aLocale); return this; } @@ -306,19 +317,4 @@ private Map> toMap() { // NOPMD return Map.of(myLocale.toLanguageTag(), myStrings); } - /** - * Checks the language tag of the supplied Locale. If the language tag is "und" the Locale is undefined and an - * IllegalArgumentException is thrown. - * - * @param aLocale A locale - * @return The valid locale - * @throws IllegalArgumentException If the supplied locale is not a pre-defined locale - */ - private Locale checkLangTag(final Locale aLocale) { - if ("und".equals(aLocale.toLanguageTag())) { - throw new IllegalArgumentException(LOGGER.getMessage(MessageCodes.JPA_020, aLocale.getDisplayName())); - } - - return aLocale; - } } diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18nProperty.java b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18nProperty.java index baf9b865..07a096db 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18nProperty.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/I18nProperty.java @@ -7,18 +7,19 @@ import java.util.Map; import java.util.Objects; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonValue; import info.freelibrary.util.Logger; import info.freelibrary.util.LoggerFactory; import info.freelibrary.util.StringUtils; +import info.freelibrary.iiif.presentation.v3.utils.I18nUtils; import info.freelibrary.iiif.presentation.v3.utils.MessageCodes; /** * A base class for label, summary, attribution, property, and metadata's label and value fields. */ +@SuppressWarnings("PMD.AvoidDuplicateLiterals") class I18nProperty> { /** @@ -42,25 +43,28 @@ class I18nProperty> { } /** - * Creates a property from an array of string(s). + * Creates a property from a matrix of internationalization values. * - * @param aStringArray An array of strings for the property + * @param aHtmlAllowed Whether HTML is allowed in the internationalization values + * @param aI18nMatrix A matrix of internationalization values + * @throws IllegalArgumentException If the supplied matrix isn't valid */ - I18nProperty(final String... aStringArray) { - myI18ns = new ArrayList<>(); - addCheckedStrings(aStringArray); + @SuppressWarnings("PMD.UseVarargs") + I18nProperty(final boolean aHtmlAllowed, final String[][] aI18nMatrix) { + myI18ns = List.of(I18nUtils.createI18ns(aHtmlAllowed, null, aI18nMatrix)); } /** - * Sets the string value of the property, removing all other previous strings. + * Creates a property from a matrix of internationalization values. * - * @param aStringArray A string value - * @return True if the property's value was set + * @param aHtmlAllowed Whether HTML is allowed in the internationalization values + * @param aDefaultLangTag A default language tag that can be used with the matrix + * @param aI18nMatrix A matrix of internationalization values + * @throws IllegalArgumentException If the supplied matrix isn't valid */ - @JsonIgnore - protected I18nProperty setStrings(final String... aStringArray) { - myI18ns.clear(); - return addCheckedStrings(aStringArray); + @SuppressWarnings("PMD.UseVarargs") + I18nProperty(final boolean aHtmlAllowed, final String aDefaultLangTag, final String[][] aI18nMatrix) { + myI18ns = List.of(I18nUtils.createI18ns(aHtmlAllowed, Objects.requireNonNull(aDefaultLangTag), aI18nMatrix)); } /** @@ -74,6 +78,35 @@ protected I18nProperty setI18ns(final I18n... aI18nArray) { return addCheckedI18ns(aI18nArray); } + /** + * Sets the internationalizations of the property from the supplied matrix of values. + * + * @param aHtmlAllowed Whether HTML is allowed in internationalized values + * @param aI18nMatrix A matrix of values to be turned into internationalizations in the property + * @return An I18n property + */ + @SuppressWarnings("PMD.UseVarargs") + protected I18nProperty setI18ns(final boolean aHtmlAllowed, final String[][] aI18nMatrix) { + myI18ns.clear(); + return addCheckedI18ns(I18nUtils.createI18ns(aHtmlAllowed, null, aI18nMatrix)); + } + + /** + * Sets the internationalizations of the property from the supplied matrix of values and a default language tag. + * + * @param aHtmlAllowed Whether HTML is allowed in internationalized values + * @param aDefaultLangTag A default language tag to use if one isn't supplied in the matrix + * @param aI18nMatrix A matrix of values to be turned into internationalizations in the property + * @return An I18n property + */ + @SuppressWarnings("PMD.UseVarargs") + protected I18nProperty setI18ns(final boolean aHtmlAllowed, final String aDefaultLangTag, + final String[][] aI18nMatrix) { + myI18ns.clear(); + return addCheckedI18ns( + I18nUtils.createI18ns(aHtmlAllowed, Objects.requireNonNull(aDefaultLangTag), aI18nMatrix)); + } + /** * Gets a list of the property's internationalizations. * @@ -155,23 +188,40 @@ public String toString() { } /** - * Adds a string value to the property. + * Adds an internationalization to the property. * - * @param aStringArray An array of strings to add to the property + * @param aI18nArray A list of internationalizations * @return The property */ - protected I18nProperty addStrings(final String... aStringArray) { - return addCheckedStrings(aStringArray); + protected I18nProperty addI18ns(final I18n... aI18nArray) { + return addCheckedI18ns(aI18nArray); } /** - * Adds an internationalization to the property. + * Adds an internationalization to the property in the form of a matrix of values. * - * @param aI18nArray A list of internationalizations + * @param aHtmlAllowed Whether the internationalization values can contain HTML + * @param aI18nMatrix A matrix of values to turn into internationalizations * @return The property */ - protected I18nProperty addI18ns(final I18n... aI18nArray) { - return addCheckedI18ns(aI18nArray); + @SuppressWarnings("PMD.UseVarargs") + protected I18nProperty addI18ns(final boolean aHtmlAllowed, final String[][] aI18nMatrix) { + return addCheckedI18ns(I18nUtils.createI18ns(aHtmlAllowed, null, aI18nMatrix)); + } + + /** + * Adds an internationalization to the property in the form of a matrix of values. + * + * @param aHtmlAllowed Whether HTML is allowed in the property's value(s) + * @param aDefaultLangTag A default language tag to use when the matrix values don't contain one + * @param aI18nMatrix A matrix of values to turn into internationalizations + * @return The property + */ + @SuppressWarnings("PMD.UseVarargs") + protected I18nProperty addI18ns(final boolean aHtmlAllowed, final String aDefaultLangTag, + final String[][] aI18nMatrix) { + return addCheckedI18ns( + I18nUtils.createI18ns(aHtmlAllowed, Objects.requireNonNull(aDefaultLangTag), aI18nMatrix)); } /** @@ -196,27 +246,6 @@ protected Object toMap() { return map; } - /** - * Adds strings to the I18nProperty after they've been checked and confirmed to not be null. - * - * @param aStringArray An array of strings - * @return The property - * @throws UnsupportedOperationException If a supplied string cannot be added as an I18n - */ - private I18nProperty addCheckedStrings(final String... aStringArray) { - Objects.requireNonNull(aStringArray, MessageCodes.JPA_001); - - for (final String string : aStringArray) { - Objects.requireNonNull(string, MessageCodes.JPA_001); - - if (!myI18ns.add(new I18n(I18n.DEFAULT_LANG, string))) { - throw new UnsupportedOperationException(LOGGER.getMessage(MessageCodes.JPA_043, string)); - } - } - - return this; - } - /** * Adds internationalized values to the I18nProperty after they've been checked and confirmed to not be null. * diff --git a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/Label.java b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/Label.java index 67ffe93d..055410ab 100644 --- a/src/main/java/info/freelibrary/iiif/presentation/v3/properties/Label.java +++ b/src/main/java/info/freelibrary/iiif/presentation/v3/properties/Label.java @@ -1,8 +1,9 @@ package info.freelibrary.iiif.presentation.v3.properties; +import java.util.Objects; + import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import info.freelibrary.iiif.presentation.v3.utils.I18nUtils; @@ -14,8 +15,28 @@ * between pages or between a choice of images to display. */ @JsonDeserialize(using = LabelDeserializer.class) +@SuppressWarnings("PMD.AvoidDuplicateLiterals") public class Label extends I18nProperty