Expand my Community achievements bar.

Dive into Adobe Summit 2024! Explore curated list of AEM sessions & labs, register, connect with experts, ask questions, engage, and share insights. Don't miss the excitement.
SOLVED

Dynamic sitemap generator

Avatar

Level 1

Hello, I have tried to create a dynamic sitemap generator using a servlet, I would like to help me by leaving your recommendations to optimize the code or a better way to achieve the creation of a dynamic sitemap.

The idea is to allow the author, to select whether or not the pages will appear on the sitemap, the way in which this is done will not be placed, but basically it will allow using the hideInSitemap fields, whose value will be true or false, in order to create the mapping.

 

class SitemapGenerator:

package es.hesperia.web.terrum.core.servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.activation.UnsupportedDataTypeException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.Servlet;

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.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
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;
@Component(service = Servlet.class, property = { 
		Constants.SERVICE_DESCRIPTION + "=Query Builder servlet",
		"sling.servlet.methods=" + HttpConstants.METHOD_GET, 
		"sling.servlet.paths=" + "/bin/projectSitemap"
		})
public class SitemapGenerator extends SlingSafeMethodsServlet {
	final String path = "/content/project/language-master";
	final String project = "/content/project";
	final String propertyFilterVar = "hideInSitemap"; //field to search
	final String propertyFilterValue = "false";
	final String lastModified = "cq:lastModified";//last change to the page
	final String priorityPage= "priorityPage";
	private static final long serialVersionUID = 2610051404257637265L;
	private static final Logger log = LoggerFactory.getLogger(SitemapGenerator.class);
	
	@Reference
	private transient QueryBuilder builder;
	@Override
	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
		Session session = null;
		try {
			log.debug("----------< Executing Query Builder Servlet >----------");
			ResourceResolver resourceResolver = request.getResourceResolver();
			session = resourceResolver.adaptTo(Session.class);
			Map<String, String> pages = new HashMap<>();
			pages.put("path", this.path);
			pages.put("property", this.propertyFilterVar);
			pages.put("property.1_value", this.propertyFilterValue);
			Query query = this.builder.createQuery(PredicateGroup.create(pages), session);
			query.setHitsPerPage(-1);//unlimited results
			String lastKey = "";
	        SearchResult searchResult = query.getResult();
	        PrintWriter out = response.getWriter();
	        List<List<String[]>> languageKey = new ArrayList<>();//list of pages by language
	        List<String[]> pagesList = null;//by pages
	        for(Hit hit : searchResult.getHits()) {
	        	String[] contentNode = new String[4];
	        	String pathUrl = hit.getPath();
	        	String simplePath = pathUrl;
		    	simplePath = simplePath.replaceAll(project, request.getServerName());
		    	simplePath = simplePath.replaceAll("/jcr:content", ".html");
		    	Resource rs = resourceResolver.getResource(pathUrl);//Metadata
		    	Node node = rs.adaptTo(Node.class);
		    	String actualKey = node.getAncestor(4).getPath();//arbol hasta el nivel del idioma
		    	contentNode[0] = simplePath;//
url of the page
		    	contentNode[1] = node.getProperty(lastModified).getString();//last update
		    	contentNode[2] = node.getProperty(priorityPage).getString();//priority
		    	contentNode[3] = actualKey.replace(this.path+"/", "");//format language -> [a-z]{2}
		    	/**
		    	 * if lastKey is equal to actualKey, a new list of pages is added 
		    	 * for a new language nueva
		    	 */
		    	if (!lastKey.equals(actualKey)) {
		    		/**
		    		 * when lastKey is igual to "" is the first language that is stored
		    		 * and only the page list for the first language is initialized
		    		 */
		    		if (!lastKey.equals("")) {
		    			languageKey.add(pagesList);
		    		}
		    		pagesList = new ArrayList<>();
		    		lastKey = actualKey;
		    	}
		    	int size = pagesList.size();
		    	Boolean inserted = false;
		    	int index = 0;
		    	/**
		    	 * alphabetically sorts each page, as it is added
		    	 */
		    	while (!inserted && index<size) {
		    		if (simplePath.compareTo(pagesList.get(index)[0])<0) {
		    			pagesList.add(index,contentNode);
		    			inserted = true;
		    		}
		    		index++;
		    	}
		    	/**
		    	 * if no elements were inserted into the list, it is inserted at the end of the list
		    	 */
		    	if (!inserted) {
		    		pagesList.add(contentNode);
		    	}
	        }
	        languageKey.add(pagesList);
	        int numPages = languageKey.get(0).size();
	        int numLanguages = languageKey.size();
	        response.setContentType("text/xml");
	        out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
	        out.println("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">");
			for (int i = 0; i < numPages; i++) {
				out.println("<url>");
				out.println("<loc>"+languageKey.get(numLanguages-1).get(i)[0]+"</loc>");//URL
				/**
				 * if there is more than one language the alternative links are printed
				 * for each language
				 */
				if (numLanguages > 1) {
					int size = numLanguages;
					for (int index = size-1; index>=0;index--) {
						out.println("<xhtml rel=\"alternate\" hreflang=\""+languageKey.get(index).get(i)[3]//language
								+"\" href=\""+languageKey.get(index).get(i)[0]+"\" />");//url
					}
				}
				String dateStr = languageKey.get(0).get(i)[1];//updated date
				String pattern = "\\D\\d{3}";				  //new format
				dateStr = dateStr.replaceFirst(pattern, "");
				out.println("<lastmod>"+dateStr+"</lastmod>");//last update
		    	out.println("<priority>"+languageKey.get(0).get(i)[2]+"</priority>");//priority
				out.println("</url>");
	        }
	        out.println("</urlset>");
	       	session.save();
		} catch (UnsupportedEncodingException|UnsupportedDataTypeException e) {
			log.error("UnsupportedEncodingException|UnsupportedDataTypeException:", e);
		} catch (IOException e) {
			log.error("IOException:", e);
			e.printStackTrace();
		} catch (RepositoryException e) {
			log.error("RepositoryException:", e);
			e.printStackTrace();
		} finally {
			if(session != null) {
				session.logout();
			}
		}
	}
}

This is my code, it is personalized but I would like to know other points of view to improve it or other ways of doing it.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Use Acs commons sitemap generator with simple configuration instead of developing custom logic..

View solution in original post

2 Replies

Avatar

Correct answer by
Community Advisor

Use Acs commons sitemap generator with simple configuration instead of developing custom logic..

Avatar

Level 1

Could you please share the steps for Using Acs commons sitemap generator with simple configuration instead of developing custom logic for change frequency.