diff --git a/src/main/java/edu/illinois/library/cantaloupe/image/MetaIdentifier.java b/src/main/java/edu/illinois/library/cantaloupe/image/MetaIdentifier.java index 35493f3c4..0ceb21880 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/image/MetaIdentifier.java +++ b/src/main/java/edu/illinois/library/cantaloupe/image/MetaIdentifier.java @@ -259,6 +259,34 @@ private void checkFrozen() { } } + /** + *

Translates the meta-identifier into a URI path component.

+ * + *

Reverses {@link #fromURIPathComponent(String, DelegateProxy)}.

+ * + * @param delegateProxy Delegate proxy. + */ + public String toURIPathComponent(DelegateProxy delegateProxy) { + // Encode just the identifier part. + final Identifier originalIdentifier = getIdentifier(); + final String slashedIdentifier = originalIdentifier.toString(); + final String deSlashedIdentifier = StringUtils.encodeSlashes(slashedIdentifier); + final String encodedIdentifier = Reference.encode(deSlashedIdentifier); + final MetaIdentifierTransformer xformer = + new MetaIdentifierTransformerFactory().newInstance(delegateProxy); + final String serializedMetaIdentifier; + + setIdentifier(new Identifier(encodedIdentifier)); + serializedMetaIdentifier = xformer.serialize(this); + // Now that we've serialized the encoded meta-identifier, put it back to how it was before + setIdentifier(originalIdentifier); + + LOGGER.debug("[Slash-substituted identifier: {}] -> [de-slashed identifier: {}] -> " + + "[percent-encoded identifier: {}] -> [raw path component: {}]", + slashedIdentifier, deSlashedIdentifier, encodedIdentifier, serializedMetaIdentifier); + return serializedMetaIdentifier; + } + @Override public String toString() { return new StandardMetaIdentifierTransformer().serialize(this); diff --git a/src/main/java/edu/illinois/library/cantaloupe/resource/AbstractResource.java b/src/main/java/edu/illinois/library/cantaloupe/resource/AbstractResource.java index 7b2c04e8d..812a57956 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/resource/AbstractResource.java +++ b/src/main/java/edu/illinois/library/cantaloupe/resource/AbstractResource.java @@ -13,8 +13,6 @@ import edu.illinois.library.cantaloupe.image.Format; import edu.illinois.library.cantaloupe.image.Identifier; import edu.illinois.library.cantaloupe.image.MetaIdentifier; -import edu.illinois.library.cantaloupe.image.MetaIdentifierTransformer; -import edu.illinois.library.cantaloupe.image.MetaIdentifierTransformerFactory; import edu.illinois.library.cantaloupe.delegate.DelegateProxy; import edu.illinois.library.cantaloupe.delegate.DelegateProxyService; import edu.illinois.library.cantaloupe.delegate.UnavailableException; @@ -594,9 +592,8 @@ protected Reference getPublicReference(MetaIdentifier newMetaIdentifier) { final int identifierIndex = pathComponents.indexOf( getIdentifierPathComponent()); - final MetaIdentifierTransformer xformer = - new MetaIdentifierTransformerFactory().newInstance(getDelegateProxy()); - final String newMetaIdentifierString = xformer.serialize(newMetaIdentifier); + final String newMetaIdentifierString = + newMetaIdentifier.toURIPathComponent(getDelegateProxy()); publicRef.setPathComponent(identifierIndex, newMetaIdentifierString); return publicRef; } diff --git a/src/main/java/edu/illinois/library/cantaloupe/util/StringUtils.java b/src/main/java/edu/illinois/library/cantaloupe/util/StringUtils.java index 015bf0d60..b5dec596d 100644 --- a/src/main/java/edu/illinois/library/cantaloupe/util/StringUtils.java +++ b/src/main/java/edu/illinois/library/cantaloupe/util/StringUtils.java @@ -41,6 +41,22 @@ public static String decodeSlashes(final String uriPathComponent) { return uriPathComponent; } + /** + * Reverses {@link #decodeSlashes(String)}. + * + * @param slashedIdentifier Identifier with slashes to be substituted. + * @return Identifier with slashes substituted. + */ + public static String encodeSlashes(final String slashedIdentifier) { + final String substitute = Configuration.getInstance(). + getString(Key.SLASH_SUBSTITUTE, ""); + if (!substitute.isEmpty()) { + return org.apache.commons.lang3.StringUtils.replace( + slashedIdentifier, "/", substitute); + } + return slashedIdentifier; + } + public static String escapeHTML(String html) { StringBuilder out = new StringBuilder(Math.max(16, html.length())); for (int i = 0, length = html.length(); i < length; i++) { diff --git a/src/test/java/edu/illinois/library/cantaloupe/image/MetaIdentifierTest.java b/src/test/java/edu/illinois/library/cantaloupe/image/MetaIdentifierTest.java index 13b519d46..b9a318de3 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/image/MetaIdentifierTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/image/MetaIdentifierTest.java @@ -264,6 +264,29 @@ void testSetScaleConstraintWithFrozenInstance() { () -> instance.setScaleConstraint(scaleConstraint)); } + /* toURIPathComponent() */ + + @Test + void testToURIPathComponent() { + final Configuration config = Configuration.getInstance(); + config.setProperty(Key.SLASH_SUBSTITUTE, "BUG"); + config.setProperty(Key.META_IDENTIFIER_TRANSFORMER, + StandardMetaIdentifierTransformer.class.getSimpleName()); + + DelegateProxy delegateProxy = TestUtil.newDelegateProxy(); + MetaIdentifier metaIdentifier = MetaIdentifier.builder() + .withIdentifier("cats/:dogs") + .withPageNumber(2) + .withScaleConstraint(2, 3) + .build(); + MetaIdentifier beforeMethodCall = new MetaIdentifier(metaIdentifier); + String actual = metaIdentifier.toURIPathComponent(delegateProxy); + String expected = "catsBUG%3Adogs;2;2:3"; + assertEquals(expected, actual); + // Make sure the call to toURIPathComponent didn't change the meta-identifier. + assertEquals(beforeMethodCall, metaIdentifier); + } + /* toString() */ @Test diff --git a/src/test/java/edu/illinois/library/cantaloupe/util/StringUtilsTest.java b/src/test/java/edu/illinois/library/cantaloupe/util/StringUtilsTest.java index 817c9041f..ccbfc352a 100644 --- a/src/test/java/edu/illinois/library/cantaloupe/util/StringUtilsTest.java +++ b/src/test/java/edu/illinois/library/cantaloupe/util/StringUtilsTest.java @@ -25,6 +25,13 @@ void testDecodeSlashes() { assertEquals("ca/ts", StringUtils.decodeSlashes("ca$$ts")); } + @Test + void testEncodeSlashes() { + Configuration.getInstance().setProperty(Key.SLASH_SUBSTITUTE, "$$"); + assertEquals("cats", StringUtils.encodeSlashes("cats")); + assertEquals("ca$$ts", StringUtils.encodeSlashes("ca/ts")); + } + @Test void testEscapeHTML() { String html = "the quick brown fox";