Adobe

Unit Testing JCR Resource Resolver Mappings

Website Design. Developing Programming And Coding Technologies.

Recently, I had a task to shorten URLs and remove the HTML extension in AEM. On top of that, I had to add a context root to the URLs so that these mappings would happen.

  • /content/myapp/en_US.html -> /mycontext/
  • /content/myapp/en_US/homepage.html -> /mycontext/homepage/
  • /content/myapp/es_ES.html -> /mycontext/es_ES/
  • /content/myapp/es_ES/homepage.html -> /mycontext/es_ES/homepage/

Shorting URLs in AEM consists of two things:

  • The dispatcher will receive requests for short extension-less URLs and must rewrite them before passing them through to the publishers.
  • The links within the HTML markup rendered by AEM must be rewritten to their short extension-less versions.

Setting up Apache is straight forward. You need to inspect the incoming request and translate it to its long version before sending it on to AEM. What I had trouble with was configuring the Sling mappings to rewrite URLs. There are 2 ways to achieve this:

  • Update the content under /etc/map
  • Add the mapping to the resource.resolver.mapping property of the org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl OSGi configuration

What I Do

In general, I have always opted for the second. I find it is simpler to manage than managing content under /etc/map. The only annoying thing is that if you make a change it causes every OSGi component that depends on it to restart. Having to wait a long time between changes is frustrating. This is especially true if I am trying to work out new mapping rules.

Nowadays, I find myself doing more and more TDD. In particular, I’ve been leveraging wcm.io Sling Mocks. With JUnit 5 and AssertJ, I can develop Sling Models and OSGi components without ever having to load a page.

And this is it! I wrote the unit test and then I focused on creating a set of outgoing mappings. Once satisfied, I popped them into the OSGi configuration. Then, I sat around for 7 minutes until the system became responsive again, and the job was complete!

import static org.assertj.core.api.Assertions.assertThat;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import com.google.common.collect.ImmutableMap;
import io.wcm.testing.mock.aem.junit5.*;

@ExtendWith(AemContextExtension.class)
class UrlMappingTest {

    private static final ImmutableMap<String, Object> PROPERTIES =
        ImmutableMap.of("resource.resolver.mapping", ArrayUtils.toArray(
            "/:/",
            "^/content/myapp/en_US\\.html</mycontext/",
            "^/content/myapp/en_US/(.+)\\.html</mycontext/$1/",
            "^/content/myapp/(.+)\\.html</mycontext/$1/"
        ));

    private final AemContext context =
            new AemContextBuilder().resourceResolverType(ResourceResolverType.JCR_MOCK)
                                   .resourceResolverFactoryActivatorProps(PROPERTIES)
                                   .build();

    @Test
    public void testShortExtensionlessMappings() {

        final ResourceResolver resourceResolver = this.context.resourceResolver();

        final String defaultLocaleRoot =
            resourceResolver.map("/content/myapp/en_US.html");
        assertThat(defaultLocaleRoot).isEqualTo("/mycontext/");

        final String defaultLocalePath =
            resourceResolver.map("/content/myapp/en_US/hello-world.html");
        assertThat(defaultLocalePath).isEqualTo("/mycontext/hello-world/");

        final String localeRoot =
            resourceResolver.map("/content/myapp/es_US.html");
        assertThat(localeRoot).isEqualTo("/mycontext/es_US/");

        final String localePath =
            resourceResolver.map("/content/myapp/es_US/hello-world.html");
        assertThat(localePath).isEqualTo("/mycontext/es_US/hello-world/");

        final String qsParams =
            resourceResolver.map("/content/myapp/es_US/hello-world.html?foo=bar");
        assertThat(qsParams).isEqualTo("/mycontext/es_US/hello-world/?foo=bar");
    }
}

I hope you found this blog post useful. For any additional questions, please comment below and be sure to check out our other Adobe blogs.

About the Author

Juan Ayala is a Lead Developer in the Adobe practice at Perficient, Inc., focused on the Adobe Experience platform and the things revolving around it.

More from this Author

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to the Weekly Blog Digest:

Sign Up
Categories