Expand my Community achievements bar.

Applications for the 2024-2025 Adobe Experience Manager Champion Program are open!
SOLVED

resource adapted to ContentFragment throws null in AEM service Impl

Avatar

Community Advisor

Hi All,

In my aem service impl, when I am adapting my resource to ContentFragment Object it returns null CF object.
Although my resource is not null and I can see my resource path as well. 

Thanks!

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

At the end figures out the issue, I know it was a blunder, 
I guess the issue was that we need to give permissions to /conf/myproject along with /content/dam/project.
And I guess CF api ONLY works when we have access to both. Rather Node and Resource API work with only access to /content/dam

View solution in original post

12 Replies

Avatar

Community Advisor

@krati_garg - Yes I am trying the same approach, but it gives null values after adapting the resource to CF.

Here is my code snippet:

package com.myproject.core.services.impl;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Base64;
import java.util.Collections;
import java.util.Enumeration;
import org.apache.sling.api.resource.LoginException;
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.serviceusermapping.ServiceUserMapped;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.propertytypes.ServiceRanking;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.query.Query;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.dam.cfm.ContentElement;
import com.adobe.cq.dam.cfm.ContentFragment;
import com.day.cq.commons.Externalizer;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.myproject.core.models.TeamMemberContentFragment;
import com.myproject.core.services.SearchService;

import com.myproject.core.services.TeamMemberPageService;
import com.myproject.core.utils.LinkUtils;
import org.apache.sling.api.resource.ResourceResolver;
import java.util.Optional;
import com.adobe.cq.dam.cfm.FragmentTemplate;

@Component(immediate = true, service = TeamMemberPageService.class, name = "com.myproject.core.services.TeamMemberPageService", configurationPolicy = ConfigurationPolicy.REQUIRE, property = {
"service.vendor=myproject", "service.description=myproject - Team Member Service" })
@Designate(ocd = TeamMemberPageServiceImpl.Config.class)
public class TeamMemberPageServiceImpl implements TeamMemberPageService {

public static final Logger LOGGER = LoggerFactory.getLogger(TeamMemberPageService.class);

@ObjectClassDefinition(name = "myproject - Team Mmeber Service Configuration", description = "Configuration for Team Mmeber Service Configuration.")
public @interface Config {

@AttributeDefinition(name = "Enable Create Bio Page", description = "This enables Create Dynamic Bio Page.", type = AttributeType.BOOLEAN)
public boolean enableCreateBioPage();

@AttributeDefinition(name = "Team Mmeber Source Content Fragment Path", description = "Team Mmeber Source Content Fragment Path.")
String teamMemeberSourceCfPath()

default "/content/dam/myproject/content-fragments/team-members";

@AttributeDefinition(name = "Team Mmeber Destination Page Path", description = "Team Mmeber Destination Page Path.")
String teamMemeberDestinationPagePath()

default "/content/myproject/us/en/team-members";

}

private Config config;



@Reference
private ResourceResolverFactory resourceResolverFactory;

@Activate
public void activate(Config config) {
this.config = config;

}

private Optional<ContentFragment> contentFragment;

@Override
public void createTeamMmeberPages(String path) {
LOGGER.info("Inside the Teams Service");

final Map<String, Object> authInfo = Collections.singletonMap(
ResourceResolverFactory.SUBSERVICE, "readWriteServiceUser");

try (ResourceResolver serviceResolver = resourceResolverFactory.getServiceResourceResolver(authInfo)) {

Resource resource = serviceResolver
.resolve(path);

LOGGER.info("Resource OBJECT: {} " + resource);
LOGGER.info("Resource Value: {} " + resource.getPath());

contentFragment = Optional.ofNullable(resource.adaptTo(ContentFragment.class));

LOGGER.info("CF: {} " + contentFragment);

String cfValue = contentFragment
.map(cf -> cf.getElement("name"))
.map(ContentElement::getContent)
.orElse(StringUtils.EMPTY);

LOGGER.info("content cf: {} " + cfValue);


} catch (LoginException e) {
LOGGER.error("Login Exception when obtaining a User for the Bundle Service: {} ", e);
}

}

}

Avatar

Employee Advisor

Hopefully 
/content/dam/myproject/content-fragments/team-members

This resource is a Content Fragment and not a folder or any other Asset.

 

Can you please check?

 

Also, please add the error log for the same

Avatar

Community Advisor

This is a folder in which I have all the CF stored. But I am not using this path anywhere in the code, rather I am accessing the CF inside it.

Avatar

Community Advisor

Also, I can adapt my resource to a Node without any issue in my service impl. But it doesn't resolve the resource to ContentFragment in my service impl.

It's bit weird! 

Avatar

Employee Advisor

Hi @Nikhil-Kumar 

With above comment, it feels the service user does not have required access to adapt to a Content Fragment, and just default JCR permissions.

Can you please share the ACL permissions for the readWriteServiceUser, especially over content/dam?

It should have required read/write access over Content Fragment Folder, you are trying to access in the code.

Avatar

Level 4

Try using below code, if you have the request object:

 

  • import org.apache.sling.models.factory.ModelFactory;
  • @OSGiService

         private ModelFactory modelFactory;

  • ContentFragment cf = modelFactory.getModelFromWrappedRequest(request, resource, ContentFragment.class);

https://github.com/kiransg89/LinkedContentFragment/blob/main/LinkedContentFragmentImpl.java

 

Maybe this might help!

Avatar

Community Advisor

Hi @Nikhil-Kumar ,

Can you try this?

ContentFragment CF = resourceResolver.getResource(path).adaptTo(ContentFragment.class);

or in your case

Resource resource = serviceResolver.getResource(path); //instead .resolve(path);

Regards,

Santosh

Avatar

Correct answer by
Community Advisor

At the end figures out the issue, I know it was a blunder, 
I guess the issue was that we need to give permissions to /conf/myproject along with /content/dam/project.
And I guess CF api ONLY works when we have access to both. Rather Node and Resource API work with only access to /content/dam

Avatar

Employee Advisor

Almost inline with my last comment. Hope you read it, before finding it on your own. Could have saved some of your time @Nikhil-Kumar 

Avatar

Community Advisor

@Thanks @krati_garg , I had gieven access to the /content/dam but we require permissions over /conf as well along with /content/dam