Expand my Community achievements bar.

Need help with Displaying FAQs on the Page based on the specified Tag

Avatar

Level 1

We want to display FAQs dynamically on the page based on the tags, so I wrote the Java code for that, but when I looked at the log statements, I saw that it doesn’t go inside while loop only, and also listChildren doesn’t return, so please look at the below Java code and log statements, and confirm me if I missed anything.

 

faqImpl.java

package com.amex.gcdt.models;
 
import java.util.HashMap;
import java.util.Map;
import java.lang.String;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import com.day.cq.tagging.Tag;
import javax.annotation.PostConstruct;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.ExporterOption;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.*;
import org.apache.sling.api.resource.*;
import com.day.cq.tagging.TagManager;
import com.day.cq.tagging.*;
import javax.jcr.Node;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.Page;
 
import com.amex.gcdt.constants.FaqFragmentConstants;
import com.adobe.cq.dam.cfm.ContentFragment;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
 
import com.day.cq.search.*;
import com.day.cq.search.result.*;
import com.day.cq.wcm.api.Page;
import com.day.cq.dam.api.*;
import javax.jcr.*;
import javax.inject.*;
import org.osgi.service.component.annotations.*;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.collections4.ListUtils;
 
import java.util.Iterator;
 
@Model(adaptables = { SlingHttpServletRequest.class }, adapters = { FaqImpl.class,
ComponentExporter.class }, resourceType = FaqFragmentConstants.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, selector = ExporterConstants.SLING_MODEL_SELECTOR, extensions = ExporterConstants.SLING_MODEL_EXTENSION, options = {
@ExporterOption(name = "MapperFeature.SORT_PROPERTIES_ALPHABETICALLY", value = FaqFragmentConstants.TRUE),
@ExporterOption(name = "SerializationFeature.WRITE_DATES_AS_TIMESTAMPS", value = FaqFragmentConstants.FALSE) })
public class FaqImpl implements ComponentExporter {
private static final Logger LOG = LoggerFactory.getLogger(FaqImpl.class);
@Self
private SlingHttpServletRequest request;
@ScriptVariable
private ValueMap properties;
private Page currentPage;
@SlingObject
private ResourceResolver resourceResolver;
private Tag faqTagObject;
String[] selectors;
Resource faqFragment;
List<Resource> faqFragments;
Boolean isFaqPage = FaqFragmentConstants.BOOLEAN_FALSE;
 
//PostConstruct method called after object creation
@PostConstruct
protected void init() {
try {
LOG.info("Starting FaqImpl initialization...");
// Get the FAQ path from component properties or page properties
String faqPath = properties.get(FaqFragmentConstants.FAQ_PATH, String.class);
if (faqPath == null) {
ValueMap valueMap = currentPage.getContentResource().adaptTo(ValueMap.class);
faqPath = valueMap.get(FaqFragmentConstants.FAQ_PATH, "");
}
LOG.info("FAQ Path: {}", faqPath);
// Get selectors from the request URL
selectors = request.getRequestPathInfo().getSelectors();
faqFragments = new ArrayList<>();
LOG.info("Selectors: {}", (selectors != null ? Arrays.asList(selectors) : "No selectors"));
// Check if the current page is an FAQ page based on selectors
if (selectors.length > 0) {
isFaqPage = FaqFragmentConstants.BOOLEAN_TRUE;
String cfPath = faqPath + "/" + selectors[0];
faqFragment = resourceResolver.getResource(cfPath + FaqFragmentConstants.MASTER_DATA);
LOG.info("FAQ Page detected. Added FAQ fragment: {}", faqFragment.getPath());
faqFragments.add(faqFragment);
} else {
// Get the FAQ tag from component properties
String faqTag = properties.get(FaqFragmentConstants.FAQ_TAG, String.class);
LOG.info("FAQ Tag: {}", faqTag);
ResourceResolver resourceResolver = request.getResourceResolver();
TagManager tagManager = resourceResolver.adaptTo(TagManager.class);
// Resolve the faqTag to obtain the Tag object
faqTagObject = tagManager.resolve(faqTag);
LOG.info("FAQ Tag Object: {}", faqTagObject);
if (faqTagObject != null) {
// Find resources directly associated with the tag
Resource tagResource = resourceResolver.getResource(faqTagObject.getPath());
 
LOG.info("Retrieved Resource for Tag: {}", tagResource.getPath());
Iterator<Resource> taggedResources = tagResource.listChildren();
// LOG.info("Retrieved Resource for Tag: {}", tagResource.getPath());
 
List<Resource> taggedResourcesList = IteratorUtils.toList(taggedResources);
int taggedResourcesSize = taggedResourcesList.size();
LOG.info("Size of Tagged Resources: {}", taggedResourcesSize);
 
LOG.info("Entering iterator loop for taggedResources");
while (taggedResources.hasNext()) {
Resource taggedResource = taggedResources.next();
LOG.info("Processing tagged resource: {}", taggedResource.getPath());
LOG.info("Tagged Resource: {}", taggedResource.getPath());
// Assuming the master data is stored as a child node named 'master'
Resource faqFragment = taggedResource.getChild(FaqFragmentConstants.MASTER_DATA);
if (faqFragment != null) {
LOG.info("Adding FAQ fragment: {}", faqFragment.getPath());
faqFragments.add(faqFragment);
} else {
LOG.warn("Master data not found for tagged resource: {}", taggedResource.getPath());
}
LOG.info("Processed tagged resource: {}", taggedResource.getPath());
}
LOG.info("Exiting iterator loop for taggedResources");
 
} else {
LOG.warn("FAQ TagObject is null for faqTag: {}", faqTag);
}
}
LOG.info("FaqImpl initialization completed successfully.");
LOG.info("Is FAQ Page: {}", isFaqPage);
LOG.info("FAQ Fragments: {}", faqFragments);
} catch (Exception e) {
LOG.error("Exception occurred during init", e);
}
}
public List<Resource> getFaqFragments() {
return faqFragments;
}
public Resource getFaqFragment() {
return faqFragment;
}
public Boolean getFaqPage() {
return isFaqPage;
}
public String getFaqPath() {
String reqpath = request.getRequestURI();
if (reqpath.contains(".html")) {
reqpath = reqpath.substring(0, reqpath.lastIndexOf("/") + 1) + "faq";
} else {
reqpath = reqpath + "faq";
}
return reqpath;
}
public String getExportedType() {
return "gcdtfaqdetails";
}
}
 
======
 
faqFragmentsConstants.
package com.amex.gcdt.constants;

public class FaqFragmentConstants {

public static final String RESOURCE_TYPE = "enterprise/components/content/faq";

public static final String TRUE = "true";

public static final String FALSE = "false";

public static final Boolean BOOLEAN_FALSE = false;

public static final Boolean BOOLEAN_TRUE = true;

public static final String FAQ_PATH = "faqPath";

public static final String MASTER_DATA = "/jcr:content/data";

public static final String FAQ_TAG = "faqTag";

public static final String METADATA_TAGS = "jcr:content/metadata/cq:tags";

}
HTML
<sly data-sly-test.author="${(wcmmode.edit || wcmmode.design)}">
<div class="cq-placeholder" data-emptyText="${component.title}"></div>
</sly>
<sly data-sly-use.faqsPath="${'com.amex.gcdt.models.FaqWriterUse'}" data-sly-unwrap></sly>
<sly data-sly-use.clientLib="/apps/granite/sightly/templates/clientlib.html" data-sly-call="${clientlib.all @ categories='amex.clientlib.enterprise.faq'}"></sly>
<sly data-sly-test="${properties.faqHeading}"><div class="richtext parbase pad heading-4">${properties.faqHeading}</div></sly>
<sly data-sly-test="${properties.faqTag}">
<div class="list-items pad">
<sly data-sly-use.faq="com.amex.gcdt.models.FaqImpl">
newww
<sly data-sly-list="${faq.faqFragments}">
neww222
<sly data-sly-test="${faq.faqFragments.size>1}">

<div class="faq parbase">
<div class="card">
<div class="pad-1-t pad-1-b pad-lr dls-gray-01-bg">
<div class="pad-lr text-align-left"> <a class="link-underlined text-link linkout" title="${item.questions @ context='html'}" href="${faq.getFaqPath @ extension = 'html',
selectors=item.parent.parent.cq:name}">${item.questions @ context='html'}</a> </div>
</div>
</div>
</div>
</sly>
<sly data-sly-test="${faq.faqFragments.size==1}">
<div class="container">
<div class="row">
<div class="col-md-12 col-md-offset-0 margin-0-tb">
<div class="richtext parbase pad-2-b heading-5" id="questions">${item.questions @ context='html'}</div>
<div class="border-dark-b"></div>
<div class="richtext parbase pad-2-b pad-1-t">${item.answers @ context='html'}</div>
</div>
</div>
</div>
</sly>
</sly>
</sly>
</div>
</sly>
 
Here's the Log Statements
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Starting FaqImpl initialization...
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl FAQ Path: /content/dam/amex/en-us/business/blueprint/faq-cf
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Selectors: []
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl FAQ Tag: faq:faq-topic/business-line-of-credit/loans
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl FAQ Tag Object: /content/cq:tags/faq/faq-topic/business-line-of-credit/loans
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Retrieved Resource for Tag: /content/cq:tags/faq/faq-topic/business-line-of-credit/loans
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Retrieved Resource for Tag: /content/cq:tags/faq/faq-topic/business-line-of-credit/loans
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Size of Tagged Resources: 0
28.12.2023 23:58:07.776 *WARN* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Tagged Resources is null or empty for faqTag: faq:faq-topic/business-line-of-credit/loans
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl FaqImpl initialization completed successfully.
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl Is FAQ Page: false
28.12.2023 23:58:07.776 *INFO* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] com.amex.gcdt.models.FaqImpl FAQ Fragments: []
28.12.2023 23:58:07.783 *ERROR* [10.16.228.4 [1703833087713] GET /content/amex/en-us/business/blueprint/faq-test.html HTTP/1.1] org.apache.sling.servlets.get.impl.DefaultGetServlet No renderer for extension html, cannot render resource JcrNodeResource, type=nt:unstructured, superType=null, path=/conf/onecms/settings/wcm/templates/editable-enterprise/structure/jcr:content/cq:responsive-disable




Thank You
2 Replies

Avatar

Level 2

Try passing the tag value instead of the tag path

//Try this 
// Find resources directly associated with the tag
Resource tagResource = resourceResolver.getResource(faqTag);

Instead of this 
// Find resources directly associated with the tag
Resource tagResource = resourceResolver.getResource(faqTagObject.getPath());

Avatar

Level 3
// Find resources directly associated with the tag
Resource tagResource = resourceResolver.getResource(faqTagObject.getPath());
This won't give any resources with the specified tag.  For example if the faqTagObject path is /content/cq:tags/sample then you will get the resource of /content/cq:tags/sample when you do resourceResolver.getResource and you will get child resources (ie any child tags created under sample) of this resource when you do listChildren.