Showing posts with label json. Show all posts
Showing posts with label json. Show all posts

Wednesday, 1 January 2020

A servlet to Query Pages containing particular components.

If you want to get your list of pages having particular components authored in it inside your project content folder in the form of json response, then here's a servlet for you.

The servlet is registered at path - /bin/generate/pagesreport to which you need to pass your page folder path (default is /content) and components path (separated by comma) as a query-param and it will output the list of pages (its title, path, template and component resourceType) as a json response.

What this servlet is doing is - it is forming a Predicate Map of Query having-
- path (content path from the input you provide)
- node type (nt:unstructured) 
- property (sling:resourceType)
- property value (list of components path from the input you provide)
and using it in QueryBuilder API and fetching the results in form of page node paths.

Further it is processing the hits (page node paths) from the search result to form the json response which you can consume by dong an ajax call.

This is the servlet for it-
package com.aem.community.wf.core.servlets;

import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;

import javax.jcr.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SlingServlet(paths = "/bin/generate/pagesreport")
public class PageQueryServlet extends SlingSafeMethodsServlet {

 private static final long serialVersionUID = 1L;
 private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
 @Reference
 private QueryBuilder builder;
 
 @Reference
 private ResourceResolverFactory resolverFactory;
 
 @SuppressWarnings("deprecation")
 @Override
 protected void doGet(SlingHttpServletRequest request, 
                 SlingHttpServletResponse response) throws IOException {
  
     String pageRootPath = request.getParameter("pageroot");   
     if(pageRootPath == null){
      pageRootPath = "/content";
     }
     String compType = request.getParameter("comptype");   
     if(compType == null){
      compType = "weretail/components/content/productgrid";
     }else{
      compType = compType.replace("/apps/", "");
      logger.info("Logging comp type is: "+compType);
     }
     long totalMatches = 0;
     
     response.setCharacterEncoding("UTF-8");
     response.setContentType("application/json");
     
     JSONObject json = new JSONObject();
     JSONArray jsonarray = new JSONArray();
     JSONObject tempJson;
     
     try { 
         ResourceResolver resolver = request.getResourceResolver();
         Session session = resolver.adaptTo(Session.class);
      
         Map map = new HashMap();             
         map.put("path", pageRootPath);
         map.put("type", "nt:unstructured");
         map.put("property", "sling:resourceType");
         
         String[] patharr = compType.split(",");
         for (int i=0; i<patharr.length; i++){
             map.put("property."+i+"_value", patharr[i]);
         }
         map.put("p.offset", "0");
         map.put("p.limit", "-1");
                           
         Query query = builder.createQuery(PredicateGroup.create(map), session);                    
                     
         SearchResult result = query.getResult();
         totalMatches = result.getTotalMatches();                             
         String hitpath;
         Resource pageResource;
         String pagepath;
         String jcrpagepath;
         List<String> pagesList = new ArrayList<String>();
         int pagecounter = 0;
         int compcounter = 1;
         
         for (Hit hit : result.getHits()) {
            hitpath = hit.getPath();   
            tempJson = new JSONObject();
            pagepath = hitpath.split("/jcr:content")[0];
            jcrpagepath = pagepath +"/jcr:content";
            pageResource = resolver.getResource(jcrpagepath); 
                
            if (pageResource != null && !pagesList.contains(pagepath)) { 
              pagecounter++;
              ValueMap valueMap = pageResource.getValueMap(); 
              tempJson.put("pagename", 
                            valueMap.get("jcr:title", String.class));
              tempJson.put("pagerestype", 
                            valueMap.get("sling:resourceType", String.class));
              tempJson.put("pagetemplate", 
                            valueMap.get("cq:template", String.class));
              tempJson.put("pagepath", pagepath);
              jsonarray.put(tempJson);
              pagesList.add(pagepath);
            }
         }
         json.put("totalcomponents", totalMatches);
         json.put("totalpages", pagecounter);
         json.put("pages", jsonarray);
         logger.info("Total" + totalMatches + "paths were found: \n");
         
     } catch (Exception e) {
      logger.error("Exception caught: "+e);
 }
     response.getWriter().print(json.toString());
    
    }
}

Below is the sample url to call this servlet by passing apps folder path-
http://localhost:4502/bin/generate/pagesreport?pageroot=/content&comptype=weretail/components/content/productgrid,weretail/components/content/text

And this is the screenshot of the response by hitting above url-

A servlet to Query Components inside your apps folder.

If you want to get your list of components inside your project apps folder in the form of json response, then here's a servlet for you.

The servlet is registered at path - /bin/generate/componentsreport  to which you need to pass your project folder path (default is /apps) as a query-param and it will output the list of components (their name and path) as a json response.

What this servlet is doing is - it is forming a Predicate Map of Query having the path (apps path from the input you provide) and node type (cq:Component) and using it in QueryBuilder API and fetching the results in form of component paths.
Further it is processing the hits (components path) from the search result to form the json response which you can consume by dong an ajax call.

This is the servlet for it-
package com.aem.community.wf.core.servlets;

import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;

import javax.jcr.Session;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@SlingServlet(paths = "/bin/generate/componentsreport")
public class ComponentQueryServlet extends SlingSafeMethodsServlet {

 private static final long serialVersionUID = 1L;
 private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
 @Reference
        private QueryBuilder builder;
 
 @Reference
        private ResourceResolverFactory resolverFactory;
 
 @SuppressWarnings("deprecation")
 @Override
        protected void doGet(SlingHttpServletRequest request, 
                SlingHttpServletResponse response) throws IOException {
        
  
     String compPath = request.getParameter("comppath");   
     if(compPath == null){
      compPath = "/apps";
     }
     long totalMatches = 0;
     
     response.setCharacterEncoding("UTF-8");
 response.setContentType("application/json");
     
     JSONObject json = new JSONObject();
     JSONArray jsonarray = new JSONArray();
     JSONObject tempJson;
     
     try { 
      ResourceResolver resolver = request.getResourceResolver();
      Session session = resolver.adaptTo(Session.class);
      
      Map map = new HashMap();             
         map.put("path", compPath);
         map.put("type", "cq:Component");
         map.put("p.offset", "0");
         map.put("p.limit", "-1");
                           
         Query query = builder.createQuery(PredicateGroup.create(map),
                                                                     session);                    
                     
         SearchResult result = query.getResult();
         totalMatches = result.getTotalMatches();                             
         String hitpath;
         Resource compResource;
         String compTitle;
         
         for (Hit hit : result.getHits()) {
                hitpath = hit.getPath();   
                tempJson = new JSONObject();
                
                compResource = resolver.getResource(hitpath); 
         if (compResource != null) { 
                    ValueMap valueMap = compResource.getValueMap(); 
                    compTitle = valueMap.get("jcr:title", String.class);
                    tempJson.put("componentname", compTitle);
                }
         tempJson.put("componentpath", hitpath);
         jsonarray.put(tempJson);
         }
         json.put("totalcomponents", totalMatches);
         json.put("components", jsonarray);
         logger.info("Total" + totalMatches + "paths were found: \n");
         
     } catch (Exception e) {
      logger.error("Exception caught: "+e);
 }
     response.getWriter().print(json.toString());
    
    }
}

Below is the sample url to call this servlet by passing apps folder path-
http://localhost:4502/bin/generate/componentsreport?comppath=/apps/weretail

And this is the screenshot of the response by hitting above url-



  

Sunday, 15 September 2019

Open infinity.json of your AEM page with Bookmarklet

In AEM we are often required to open .infinity.json of any page specially in author mode to see the node data tree structure in json format. infinity selector with json extension is provided by AEM OOTB for such use cases.

This is also helpful when you are debugging something related to content authored and don't want to open the page content structure in CRXDE and open each node manually till you reach that particular component node inside jcr:content of the page because it is time consuming.

Furthermore if you use .tidy.infinity.json, it will write your json data in neat and tidy way (See SS at the bottom of the post). tidy selector is also provided OOTB by AEM for tidy representation.

To use this we usually copy the editor url in new tab and append .tidy.infinity.json to the url and remove .html extension. How about if you can do this in just 1 click?

The answer is bookmarklet. A bookmarklet is a bookmark stored in a browser but instead of having a page url, it contains the JavaScript code in its URL. On click of these bookmarks, the JavaScript code executes onto your page and can modify it similar to what you would do from developer console.

So i created this very simple bookmarklet which you can run on any editor page and open infinity.json of that page in new tab in just 1 click.

javascript:(function(){ 
    var currurl = window.location.href; 
    if(currurl.indexOf('editor.html') > -1){ 
        var arr = currurl.split('.html'); 
        var newurl = arr[0].replace('/editor','')+arr[1]+'.tidy.infinity.json'; 
        window.open(newurl , '_blank'); 
    }
})();

The above logic only works in author mode as you can see i am checking if current url contains editor.html. You can modify this as per your requirement to work in publish as well.

How to use this?  

1. Click on Add page from bookmarks toolbar (similar to what you do to add any bookmark).
2. Give any Name and in the URL field copy the above code (See SS below)-



3. That's it. Now your bookmarklet is ready. To run on any page, just click on it and it will open its infinity json for yo in new tab.

See screenshots below for reference-