March 20, 2020
Estimated Post Reading Time ~

How to do URLs request Mapping in AEM/ Adobe CQ5

Mapping of request URLs in CQ/AEM
There are cases wherein we need to map the URLs during the process of the CQ request. Also, these must happen before Sling starts processing the URL.

Problem 1:
Say we need to convert the URL like: www.example.com --> converts to --> /content/mysite/en/

Analysis:
Let us see how this can be done. There are possibly many ways to do this by creating an OSGi bundle for this, to ensure that the URL is filtered by the class first and then catered by Sling.

Apache sling site(http://sling.apache.org/documentation/the-sling-engine/mappings-for-resource-resolution.html) says, "The mapping of request URL's to resources is mainly configured in a configuration tree which is (by default) located below /etc/map. The actual location can be configured with the resource.resolver.map.location property of the org.apache.sling.jcr.resource.
internal.JcrResourceResolverFactoryImpl configuration."

Thus to deal with the new resource resolution, the sling has a number of properties

sling: match -> A property to be set on a node in the /etc/map tree. A regular expression is used instead of the node's name to match the incoming request here.
sling: redirect -> This triggers a redirect response to be sent to the client, which in turn calls the client to send in a new request with the modified location.
sling: status -> Defines the HTTP status code sent to the client with the sling: redirect response.
sling:internalRedirect –> Here the current path internally gets modified to continue with resource resolution.
sling: alias –> helps the resource to indicate an alias name for the resource.

1st Solution to problem 1:
Our above problem can be handled by Sling URL Mapping.
For this we need to create a node under the /etc/map directory with a resource type of sling: Mapping (A primary node type which may be used to easily construct entries in the /etc/map tree), then match to call www.example.com.

Once an incoming request matches the node name in the above case, this then takes a property of sling:internalRedirect & this property is appended to the path to continue with internal resource resolution as shown below.

<map>
<http jcr:primaryType="sling:OrderedFolder">
<www.example.com
jcr:primaryType="sling:Mapping"
sling:internalRedirect="/content/mysite/en"/>
</http>
</map>

The above will ensure any request coming to www.example.com is resolved to www.example.com/content/mysite/en/.

2nd Solution to problem 1:
Say you need a code-based solution for multiple websites and you are not interested in managing /etc/map, you can set up your own filter as below.

package your.package;
import org.apache.felix.scr.annotations.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;

@Component(immediate=true, enabled=true)
@Service(value=Filter.class)
@Properties({
@Property(name="sling.filter.scope", value="REQUEST", propertyPrivate=true),
@Property(name="service.ranking", intValue=-10000, propertyPrivate=true)
})
public class URLFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(ProductSEOFilter.class);

@Activate
protected void activate(ComponentContext ctx) throws Exception {
}

@Deactivate
protected void deactivate() throws Exception {
}

public void init(FilterConfig filterConfig) throws ServletException {
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, ServletException {
String lang = "en";

// 1. get domain and path
// 2. check if your conditions are met
// 3. extract language from domain
// 4. internal redirect

RequestDispatcher dispatch = request.getRequestDispatcher("/content/mysite/" + lang);
dispatch.forward(request, response);
}

public void destroy() {
}
}

Problem 2:
Say we need to implement case insensitivity in URL in our CQ application like test.html and TEST.HTML directs to the same page

Analysis:
While trying to use Apache mod_rewrite and mod_speling we can find they both having some undesired effects on various types of requests. An option could be to create a request filter for this, but having multiple URLs for the same page is not recommended for SEO.

Solution:

We can use mod_rewrite.c for this at your HTTP server so that the CMS system remains untouched. The best-known pattern approach for CQ is to keep AEM content pages lowercase with no underscores and have http server convert url requests to lower case. Doing url clean up on the webserver level improves your dispatcher caching options too.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.