Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Using Context Aware Configuration Collection

Avatar

Level 3

I created a CAC Configuration with the collection = true like this (redacting real values and field names)

package com.cws.aem.core.beans.caconfigs;

import org.apache.sling.caconfig.annotation.Configuration;
import org.apache.sling.caconfig.annotation.Property;

@Configuration(label = "Some Configuration", collection = true)
public @interface SomeConfiguration{
@Property(label = "Field A", order = 1)
String fieldA();

@Property(label = "Field B", order = 6)
String fieldB();
}

 When I try to use the configuration above I used the following code

 

        resource = getRequest().getRequestPathInfo().getSuffixResource();
resourceResolver = resource.getResourceResolver();
collection = resourceResolver.adaptTo(PageManager.class).getContainingPage(resource)
.getContentResource().adaptTo(ConfigurationBuilder.class).asCollection(SomeConfiguration.class);

I step through the logic with the JVM debugger, I can actually see the resource nodes for the configurations I stored. I don't know how to access that data though and render the values in the HTL template.

 

johns43992246_0-1677524500001.png

 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @johns43992246,
As I understood, You have two requirements. Let me give you another solution.
1. Populate dialog dropdown from CA config(collection type).
 Create a servlet which serve as datasource. 

@Component(service = Servlet.class)
@SlingServletResourceTypes(
        methods = {HttpConstants.METHOD_GET},
        resourceTypes = "aemgeeks/components/datasource/dropdown"
)
public class DataSourceServlet extends SlingAllMethodsServlet {
    private static final Logger LOG = LoggerFactory.getLogger(DataSourceServlet.class);
    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
            Resource resource = request.getRequestPathInfo().getSuffixResource();
            PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
            Page formPage = pageManager.getContainingPage(resource);
            List<Resource> list = new ArrayList<>();
            InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(formPage.getContentResource());
            String ctxConfigPath = ivm.getInherited("sling:configRef", String.class);
            if (StringUtils.isNotEmpty(ctxConfigPath)) {
                String apiConfigRoot =ctxConfigPath +"/sling:configs/"+ SomeConfiguration.class.getCanonicalName();
                Resource apiResource = request.getResourceResolver().getResource(apiConfigRoot);
                apiResource.listChildren().forEachRemaining(child -> {
                    ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
                    vm.put("text", child.getValueMap().get("fieldA", String.class));
                    vm.put("value", child.getValueMap().get("fieldA", String.class));
                    list.add(new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(),
                            "nt:unstructured", vm));
                });
                DataSource dataSource = new SimpleDataSource(list.iterator());
                request.setAttribute(DataSource.class.getName(), dataSource);
            }
    }
}

Dropdown Dialog field- Use resourceType used in servlet as datasource for dropdown 

                    <caconfig
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/select"
                        fieldLabel="CA Configs"
                        name="./caconfig">
                        <datasource
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="aemgeeks/components/datasource/dropdown"/>
                    </caconfig>


2. Now if you need same CA Config values in Sighlty, use Sling model to get CA Config values.
Sling Model: 

    public List<SomeConfiguration> getConfigList() {
        InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(currentPage.getContentResource());
        String ctxConfigPath = ivm.getInherited("sling:configRef", String.class);
        String apiConfigRoot =ctxConfigPath +"/sling:configs/"+ SomeConfiguration.class.getCanonicalName();
        Resource configResource=resourceResolver.getResource(apiConfigRoot);
        Collection<SomeConfiguration> configs=configResource.adaptTo(ConfigurationBuilder.class).asCollection(SomeConfiguration.class);
        return new ArrayList<SomeConfiguration>(configs);
    }

Sightly Code - As you have entire CA Config object in list, you can get any data.

<div data-sly-use.config="com.aem.geeks.core.models.CAConfig"></div>
<div data-sly-list.item="${config.configList}">
 <p> Config : <b>${item.fieldA} </b></p>
</div>


 

View solution in original post

6 Replies

Avatar

Community Advisor

HI @johns43992246 

 

Once you get the collection, you can iterate it through the data-sly-list in htl

 

Collection<CAConfig> CAConfigs
<ul data-sly-list.collection="${classObject.CAConfigs}" data-sly-unwrap>
  <li>${collection.configValue}</li> </ul>

 

Hope it helps!

Thanks,
Kiran Vedantam.

Avatar

Level 3

I'm actually trying to pass these values in as part of a data query for a dropdown in authoring dialog. So there needs to be some transformation here from the array to the DataSource class object. If I could figure out how to get the ValueMap of each child node in the collection, I think I can handle the transformation logic.

Avatar

Community Advisor

My query is why are you trying to populate the config values in the drop-down? Ideally, they should be authored on the page. Anyways, for your use case you can try this Map code

 

HTL-code:

<div data-sly-use.hashmap="com.adobe.examples.htl.core.hashmap.HashMapExample"
     data-sly-list="${hashmap.map.keySet.iterator}">
     ${item}
     <ul data-sly-list.aem="${hashmap.map[item].keySet.iterator}">
         <li>${aem} ${hashmap.map[item][aem]}</li>
     </ul>
</div>

 

Hope it helps!

Thanks,
Kiran Vedantam.

Avatar

Level 3

For this use case I am trying to pass the properties as options in component configuration dialog. I would like use a data query which we have done previously for dynamically generated dropdown options:

 

<dialogNode
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="component field"
fieldLabel="field label"
name="./field">
<datasource
jcr:primaryType="nt:unstructured"
sling:resourceType="/resource/path/file.html"/>
</dialogNode>

file.html would have this HTL where SomeDataSource is the JavaClass that generates the options for the dropdown.

<div data-sly-use.info="${'com.cws.aem.core.datasource.SomeDataSource'}" data-sly-unwrap></div>

I have this already mapped out for another data source query so I would like to just transform the data from the child resource nodes to fit that query output.

Avatar

Correct answer by
Community Advisor

Hi @johns43992246,
As I understood, You have two requirements. Let me give you another solution.
1. Populate dialog dropdown from CA config(collection type).
 Create a servlet which serve as datasource. 

@Component(service = Servlet.class)
@SlingServletResourceTypes(
        methods = {HttpConstants.METHOD_GET},
        resourceTypes = "aemgeeks/components/datasource/dropdown"
)
public class DataSourceServlet extends SlingAllMethodsServlet {
    private static final Logger LOG = LoggerFactory.getLogger(DataSourceServlet.class);
    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
            Resource resource = request.getRequestPathInfo().getSuffixResource();
            PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
            Page formPage = pageManager.getContainingPage(resource);
            List<Resource> list = new ArrayList<>();
            InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(formPage.getContentResource());
            String ctxConfigPath = ivm.getInherited("sling:configRef", String.class);
            if (StringUtils.isNotEmpty(ctxConfigPath)) {
                String apiConfigRoot =ctxConfigPath +"/sling:configs/"+ SomeConfiguration.class.getCanonicalName();
                Resource apiResource = request.getResourceResolver().getResource(apiConfigRoot);
                apiResource.listChildren().forEachRemaining(child -> {
                    ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());
                    vm.put("text", child.getValueMap().get("fieldA", String.class));
                    vm.put("value", child.getValueMap().get("fieldA", String.class));
                    list.add(new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(),
                            "nt:unstructured", vm));
                });
                DataSource dataSource = new SimpleDataSource(list.iterator());
                request.setAttribute(DataSource.class.getName(), dataSource);
            }
    }
}

Dropdown Dialog field- Use resourceType used in servlet as datasource for dropdown 

                    <caconfig
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/select"
                        fieldLabel="CA Configs"
                        name="./caconfig">
                        <datasource
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="aemgeeks/components/datasource/dropdown"/>
                    </caconfig>


2. Now if you need same CA Config values in Sighlty, use Sling model to get CA Config values.
Sling Model: 

    public List<SomeConfiguration> getConfigList() {
        InheritanceValueMap ivm = new HierarchyNodeInheritanceValueMap(currentPage.getContentResource());
        String ctxConfigPath = ivm.getInherited("sling:configRef", String.class);
        String apiConfigRoot =ctxConfigPath +"/sling:configs/"+ SomeConfiguration.class.getCanonicalName();
        Resource configResource=resourceResolver.getResource(apiConfigRoot);
        Collection<SomeConfiguration> configs=configResource.adaptTo(ConfigurationBuilder.class).asCollection(SomeConfiguration.class);
        return new ArrayList<SomeConfiguration>(configs);
    }

Sightly Code - As you have entire CA Config object in list, you can get any data.

<div data-sly-use.config="com.aem.geeks.core.models.CAConfig"></div>
<div data-sly-list.item="${config.configList}">
 <p> Config : <b>${item.fieldA} </b></p>
</div>


 

Avatar

Level 3

Thanks, this works, I adapted it to the

com.adobe.granite.ui.components.ds.DataSource

without needing a servlet. However, I am not able to replicate the child nodes to the /conf path when I publish. This probably should be a separate question though.