Thursday, 5 June 2014

Mapping of request URLs in CQ/AEM

Mapping of request URLs in CQ

There are cases where in we need to map the URL's during the process of 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/

Anaylsis:

Let us see how this can be done. There are possible 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, sling have a number of properties

sling:match -> A property to be set on a node in the /etc/map tree. A regular expression which 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 inturn 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 the 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 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 the problem 1:

Say you need code-based solution for multiple websites and you are not interested in managing /etc/map, you can setup 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 same page

Anaylsis:
While trying to use Apache mod_rewrite and mod_speling we can find they both having some undesired effects on various type of requests. Option could be to create a request filter for this, but having multiple URL's for the same page is not recommended for SEO.

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

https://www.youtube.com/channel/UCbDTGaDneAbj_RCX27VE4cA/videos



Subscribe Our YouTube Channel Here.
Read More: 

No comments:

Post a comment