Thursday, November 13, 2014

How to use impression Service In CQ/AEM

Use Case:
  1. You often have case where you want to use Impression service provided by CQ to do custom operation for example finding top 10 most viewed page or sorting all page based on there popularity.
  2. It might possible that your impression data (Page Views) is in external system and then you want to import those data as impression in CQ to have more application context.
  3. You want to aggregate all data across all publish instances.
Solutions:

Approach 1:

Creating your Own Impression service

You can create your own impression service by extending com.day.crx.statistics.Entry here is example
Supporting class



You need to embed following dependency for this
Here is example of how you can use this service

Now you can import data from external system (GA, Site Catalyst, Kafka) and then populate it using this service to your instance.

Once you are ready with all data you can use following service to use data,



Actual Implementation


Approach 2:

You don't want to write your own service as mentioned in Approach 1 and use OOTB service available to you. Only problem with this is, You have multiple publish instance and some how you want to combine all data in to one so that you get accurate picture. It kind of tricky to get all data from all publish instance (through reverse replication) and then combine them on author and then push them over again. However you can use one instance to collect all stat data (king of single source of truth and then replicate it back to all instance every day)


  • Make sure that you enable page view tracking by adding following line

           <cq:include script="/libs/foundation/components/page/stats.jsp" />
  • Then configure all publish instance to point to one DNS using following config (You can always override this under /apps)
           /apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatistics
          /apps/wcm/core/config.publish/com.day.cq.wcm.core.stats.PageViewStatisticsImpl
         
  • make sure that pageviewstatistics.trackingurl is pointing to single domain (You need to create a domain, something like impression.mydomain.com that will be stand alone CQ instance to take all impression request)
  • Now you have consolidated page impression on one machine
  • You can easily write a schedular which will run every night and reverse replicate all data to author instance.
  • Once it is on author instance you can use replicator service to replicate to all other publish instance
  • Then you can use code mention in approach 1 to get popular resources.

Note: You can always use GA or something to track data. This is more useful if you want to do something internally and not want top share data with GA.

As usual feel free to ask any question you have.





Friday, November 7, 2014

How to make Instances SSL context aware in CQ/AEM

Use Case:

Most of the times we terminate SSL on load balancer or at dispatcher and communication to publish happen over http. In this case publish server is often not SSL aware and any request specific operations (For example relative path redirect or Link rewriting) happens over http. For example if you do something like request.sendRedirect("/somepath") from server it will get redirected to http://server-name/somepath or when you will do request.isSecure() it will return false. Operations like externalizer.externalLink(resolver, "mydomain", "/my/page") + ".html"; will also return http version of link.

Solution:

Option 1:

Let all links be http and then do force redirect on dispatcher or Load Balancer. For dispatcher rule can be as simple as this,

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [L,R=301]

Issue:

  • Not SEO friendly (Unless it is relative link).  
  • Can not embed as portlet or Iframe (Cross Site include error) over https.

Option 2: 


If filter is configured, it looks for header configured in configuration and if header value matches configured value context on publish is considered secure and request.isSecure() will return true.




In above case if X-Forwarded-SSL is present with value on then servlet context is secure.

Note: This might not work in version latest CQ version. You can build your own version from trunk https://github.com/apache/felix/tree/trunk/http/sslfilter or from http://svn.apache.org/repos/asf/felix/trunk/http/sslfilter/

One working version of file can be downloaded from here

As usual let me know if you have any question. Special thanks to Shenghao Huang from LinkedIn for finding this.

Wednesday, November 5, 2014

How to use Sling Models in CQ5.6

Use Case: Use Sling Model in CQ5.6

Background: Sling model http://sling.apache.org/documentation/bundles/models.html brings powerful way of mapping your resources to Java Objects (Beans) . It is supported OOTB in CQ6 however we can use it in CQ5.6 as well.

Solution:

First add sling models as dependency in your code (In Parent pom using dependency manager is preferred)

Then update your reactor pom (Which actually creates your CQ package using content-package-maven-plugin) you need to add following as dependency and then embed them in to your project (If install path for system is not present you can use any other path you want)

Thats it .. Models are available as service in your OSGI environment.



 To use model go ahead and create your own bundle and them add these as dependency. You should be able to write, deploy and run code against model. Note that you might have to make these model available to osgi using Sling-Model-Packages



Once model is deployed correctly you should be able to see them under sling-model tab in status in felix console or by going to HOST:PORT/system/console/status-slingmodels



Some example code using models

Some common How to

How can I inject services in Sling Model

by using annotation @OSGIService Or Using Injector @Inject @Source("osgi-service") 

Example:

@OSGIService
MyService myService

@Inject @Source("osgi-service")
MyService myService


How Can I Inject Sling Object in Sling Model

by using annotation @SlingObject Or Using Injector @Inject @Source("sling-object") 

Example:

@SlingObject
ResourceResolver resourceResolver

@Inject @Source("sling-object")
ResourceResolver resourceResolver


How Can I get access to property if adapting through Sling Request

If you are adapting your model to sling request you might not have access to property by just doing @Inject. You have to use @Via in that case. Note that you can use all other annotation here like @Named and all. Here is example

@Model(adaptables=SlingHttpServletRequest.class)
public interface MyModel { 
 
    @Inject @Via("resource")
    String propertyName;
}

How Can I use Sling Tag Library with Sling Model

You can use <sling:adaptTo ... /> or ${sling:adaptTo ...} as mentioned in https://sling.apache.org/documentation/bundles/models.html and https://sling.apache.org/documentation/bundles/sling-scripting-jsp-taglib.html .In 5.6 you might have to change global.jsp to use
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling" %>
instead of
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %>

How Can I provide default value to property in Sling Model

By using @Default Annotation . Here is example

A default value can be provided (for Strings & primitives) and Array:
@Model(adaptables=Resource.class)
public class MyModel {

    @Inject @Default(values="defaultValue")
    private String name; 
    @Inject @Default(intValues={1,2,3,4})
    private int[] integers; 
}

How Can I inject child resource as Model in Sling Model 

This can be done by Injecting a model in other model class. Here is example


@Model(adaptables=Resource.class)
public interface MyModel {

    @Inject
    ImageModel getImage();
}

@Model(adaptables=Resource.class)
public interface ImageModel {

    @Inject
    String getPath();
}

When a resource is adapted to MyModel, a child resource named image is automatically adapted to an instance of ImageModel

Note: Sling model version number can change as it evolves in future. Make sure that you update model dependencies version accordingly. You can also use Sling testing framework to test sling model which is pretty cool as well. There is also an example of deployable Model package https://github.com/Adobe-Consulting-Services/com.adobe.acs.bundles.sling-models which you can use.

As usual feel free to give your comment and feedback and let me know if you want me to add something else here.