Sunday 28 February 2016

Sling Scheduler

What is a Scheduler?

Apache Sling Scheduler enables you to easily schedule jobs within your application. Jobs can be executed at a specific time, regularly at a given period or at the time given by a cron expression by leveraging the Sling scheduler service.

Scheduling in CQ uses the open source Quartz library, part Sling Commons:‘org.apache.sling.commons.scheduler.Scheduler’. It is used to execute jobs at predefined times either periodically or at a set time. It is based on the Quartz scheduling library and can therefore make use of its syntax for defining the execution times of jobs, making it possible to precisely indicate times .

Simple Scheduler which calls Rest API:

Below scheduler writes data into JSON file which is under var folder for every 5 minutes.

package com.geometrixx.sightly.Schedulers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.HashMap;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.ValueFactory;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@Component( metatype=true, immediate = true, label = "Gaurdian API Scheduler" )
@Properties({
@Property(label = "Scheduler Label", name = "scheduler.label", value = "News Scheduler"),
@Property(label = "Scheduler Name", name = "scheduler.name", value = "News Scheduler"),
@Property(label = "Article/Event xml Scheduler Expression", name = "gaurdian.scheduler.expression", value = "0 0 * * * ?")
})
public class GuardianAPIScheduler {

Logger  log = LoggerFactory.getLogger(this.getClass());

@Reference
    private Scheduler scheduler;

@Reference
private ResourceResolverFactory resourceResolverFactory;

protected void activate( ComponentContext ctx ) throws Exception {
final Runnable newsJob = new Runnable() {
            public void run() {
            try{
               log.debug("Executing My API Scheduler");
               GuardianAPIScheduler guardianAPIScheduler = new GuardianAPIScheduler();
               guardianAPIScheduler.generateJsonFile();
            }catch(Exception e){
            log.error("Error while getting data from Api");
            }
            }
        };
        try {        
        final String eventSchedulerExp = PropertiesUtil.toString(ctx.getProperties().get("gaurdian.scheduler.expression"), "0 0 * * * ?");
            this.scheduler.addJob("news-job", newsJob, new HashMap<String, Serializable>(), eventSchedulerExp, false);
            
        } catch (Exception e) {
        newsJob.run();
        }
}

protected void generateJsonFile() throws Exception{
// TODO Auto-generated method stub
HttpClient httpClient = new HttpClient();
        GetMethod post = new GetMethod("http://content.guardianapis.com/search?q=debates&api-key=test");
        int statusCode = httpClient.executeMethod(post);
        log.debug("Status Code {}",statusCode);
        String responseBody = post.getResponseBodyAsString();
        InputStream inputStream = new ByteArrayInputStream( responseBody.getBytes() );
        ResourceResolver resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
        Session session = resourceResolver.adaptTo(Session.class);
        ValueFactory valueFactory = session.getValueFactory();
Binary contentValue = valueFactory.createBinary( inputStream );
Node varNode = JcrUtils.getOrAddNode(session.getRootNode(), "var", "sling:Folder");
Node reportNode = JcrUtils.getOrAddNode( varNode, "newsapi", "sling:Folder" );
Node reportFile = JcrUtils.getOrAddNode( reportNode, "newsapi.json" , "nt:file" );
Node jcrContentNode = JcrUtils.getOrAddNode( reportFile, "jcr:content", "nt:resource" );
jcrContentNode.setProperty( "jcr:mimeType", "application/json" );
jcrContentNode.setProperty( "jcr:data", contentValue );
log.debug("Reponse from API writing done {}",responseBody);
session.save();
}

}
  
Checking the scheduler status and other info can done under this path

http://localhost:4502/system/console/status-slingscheduler

Reference for Cron Expression:
http://www.docjar.com/docs/api/org/quartz/CronTrigger.html

Tuesday 23 February 2016

Custom Event Listener In AEM

Introduction

You can develop a custom event handler for Adobe Experience Manager (AEM)

Listerner Class:

package com.geometrixx.sightly.Listeners;

import java.util.Arrays;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.tagging.JcrTagManagerFactory;
import com.day.cq.tagging.Tag;
import com.day.cq.tagging.TagManager;



@Component
public class TagListener implements EventListener {

private final Logger LOGGER = LoggerFactory
.getLogger(TagListener.class);
private BundleContext bundleContext;
@Reference
    private ResourceResolverFactory resolverFactory;
private static final String NAMESPACE = "/etc/tags/mysample";
@Reference
    JcrTagManagerFactory tmf;
private Session session;
private ObservationManager observationManager;
public void run() {
LOGGER.info("Running...");
    }
protected void activate(ComponentContext ctx) {
        this.bundleContext = ctx.getBundleContext();
          
        try
        {
                     
            //Invoke the adaptTo method to create a Session 
             ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);
             session = resourceResolver.adaptTo(Session.class);
               
            // Setup the event handler to respond to a new claim under content/claim.... 
                
             
                 observationManager = session.getWorkspace().getObservationManager();
                final String[] types = { "cq:Page","nt:unstructured"};
                final String path = "/content"; // define the path
                observationManager.addEventListener(this, Event.NODE_ADDED, path, true,
        null, null, true);
                LOGGER.info("Observing property changes to {} nodes under {}", Arrays.asList(types), path);
                          
         }
        catch(Exception e)
        {
            LOGGER.error("unable to register session",e);
              
         }
        }
protected void deactivate(ComponentContext componentContext) throws RepositoryException {
        
        if(observationManager != null) {
            observationManager.removeEventListener(this);
        }
        if (session != null) {
            session.logout();
            session = null;
          }
    }
@Override
public void onEvent(EventIterator it) {
// TODO Auto-generated method stub
LOGGER.info("IN ONEVENT!");
        
        
        try {
            while (it.hasNext()) {
               //Custom Logic Goes Here.
  
                
            }
        }catch (Exception e) {
        LOGGER.error(e.getMessage(), e);
        }
 
}
    
}


Above class is sample Event Listener Class customize the business logic in OnEvent method which is overridden 

To get more info on Events properties please refer the documentation
https://www.day.com/maven/jsr170/javadocs/jcr-2.0/javax/jcr/observation/Event.html

To get adobe article on Event Listener refer the article

https://helpx.adobe.com/experience-manager/using/tagmanager.html

Article also describes more information about TagManager Class and to use it.

Thursday 11 February 2016

Ajax Call in Sightly component

How to make an ajax call in sightly component ???

Steps:

Follow the below steps to make an ajax call to a servlet in sightly.

1.Create a sightly component(Lets say it is component.html)
2.Create a file with name js.html under the component.
3.Write the required ajax method to invoke the servlet.
4.Include js.html in component.html

Code:

Component.html:

Here is the ajax html file included

<div data-sly-include="js.html"></div>

Js.html:

<script>
function invokeajaxCall() {
    $.ajax({
             type: 'GET',    
             url:'/libs/migration',
             success: function(msg){
alert('Method Success');
             }
         });
    }
    $(window).load(function() {

        invokeajaxCall();
    });
</script>

Component Structure: