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

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 3

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