Expand my Community achievements bar.

Get ready! An upgraded Experience League Community experience is coming in January.

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.