How to create a Json file using job? | Community
Skip to main content
Level 2
February 12, 2025
Solved

How to create a Json file using job?

  • February 12, 2025
  • 1 reply
  • 759 views

Using a job scheduler I have to create a json file in the dam that fetch the properties of a content fragment, which is always in the dam

Best answer by konstantyn_diachenko

1. OSGi Service to Process Content Fragment and Save JSON as DAM Asset
This service reads properties from a Content Fragment, converts them to JSON, and uploads the JSON as an asset in the DAM.

@8220494(service = ServiceA.class, immediate = true) public class ServiceA { private static final Logger LOG = LoggerFactory.getLogger(ServiceA.class); private static final String DAM_JSON_PATH = "/content/dam/generated-json/"; @3214626 private ResourceResolverFactory resourceResolverFactory; /** * Converts a Content Fragment to JSON and saves it as an asset in DAM */ public void processContentFragment(String contentFragmentPath) { try (ResourceResolver resolver = getServiceResourceResolver()) { Resource cfResource = resolver.getResource(contentFragmentPath); if (cfResource == null) { LOG.error("Content Fragment not found at: {}", contentFragmentPath); return; } ContentFragment contentFragment = cfResource.adaptTo(ContentFragment.class); if (contentFragment == null) { LOG.error("Invalid Content Fragment at path: {}", contentFragmentPath); return; } String jsonContent = convertContentFragmentToJson(contentFragment); saveJsonAsDamAsset(resolver, jsonContent, contentFragmentPath); } catch (Exception e) { LOG.error("Error processing Content Fragment: {}", e.getMessage(), e); } } /** * Converts Content Fragment to JSON */ private String convertContentFragmentToJson(ContentFragment contentFragment) throws IOException { Map<String, Object> data = new HashMap<>(); contentFragment.getElements().forEachRemaining(element -> data.put(element.getName(), element.getValue().getValue())); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.writeValueAsString(data); } /** * Saves JSON as a DAM asset */ private void saveJsonAsDamAsset(ResourceResolver resolver, String jsonContent, String contentFragmentPath) throws IOException { AssetManager assetManager = resolver.adaptTo(AssetManager.class); if (assetManager == null) { LOG.error("Could not adapt to AssetManager."); return; } String jsonAssetPath = DAM_JSON_PATH + getJsonFileName(contentFragmentPath); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(jsonContent.getBytes())) { Asset asset = assetManager.createAsset(jsonAssetPath, inputStream, "application/json", true); if (asset != null) { LOG.info("JSON asset created at {}", jsonAssetPath); } } } /** * Generate a unique JSON file name */ private String getJsonFileName(String contentFragmentPath) { return contentFragmentPath.replace("/content/dam/", "").replace("/", "_") + ".json"; } /** * Get service user resource resolver */ private ResourceResolver getServiceResourceResolver() throws LoginException { Map<String, Object> params = new HashMap<>(); params.put(ResourceResolverFactory.SUBSERVICE, "content-fragment-service"); return resourceResolverFactory.getServiceResourceResolver(params); } }

 2. Sling Job to Execute the Service
A Sling Job will call the above service to process Content Fragments.

@8220494( service = JobConsumer.class, property = { JobConsumer.PROPERTY_TOPICS + "=com/example/jobs/processContentFragment" } ) public class ContentFragmentJob implements JobConsumer { private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentJob.class); @3214626 private ContentFragmentToJsonService contentFragmentToJsonService; @9944223 public JobResult process(Job job) { String contentFragmentPath = job.getProperty("contentFragmentPath", String.class); if (contentFragmentPath == null) { LOG.error("Content Fragment path not provided in job."); return JobResult.FAILED; } LOG.info("Processing Content Fragment: {}", contentFragmentPath); contentFragmentToJsonService.processContentFragment(contentFragmentPath); return JobResult.OK; } }

 3. How to Trigger the Sling Job

A Sling Job can be manually triggered from the Java code, or via a scheduler, workflow, or event listener.

@8220494(service = ContentFragmentJobTrigger.class) public class ContentFragmentJobTrigger { private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentJobTrigger.class); private static final String JOB_TOPIC = "com/example/jobs/processContentFragment"; @3214626 private JobManager jobManager; public void triggerJob(String contentFragmentPath) { Map<String, Object> jobProperties = new HashMap<>(); jobProperties.put("contentFragmentPath", contentFragmentPath); jobManager.addJob(JOB_TOPIC, jobProperties); LOG.info("Job triggered for Content Fragment: {}", contentFragmentPath); } }

 

However, I would also consider another approach with servlet that will be mapped to some selector. It will allow you to request content fragment path with selector and json extension and get required data without persisting it. For example: /content/dam/cfs/my-cf.consumer-1.json. 

This is because AssetManager.createAsset is working in AEM on prem, but it's deprecated in AEMaaCS. 

 

Best regards,

Kostiantyn Diachenko. 

1 reply

konstantyn_diachenko
Community Advisor
Community Advisor
February 12, 2025

Hi @vodjakxa ,

 

Let me rephrase your question. You have content fragment and you need to read properties from content fragment and save them as a separate asset (JSON) to the DAM. Is that right?  

 

Then I have the following questions:

1) Are you using AEM on prem or AEMaaCS?

2) Is it supposed that some consumer will get this JSON file from AEM?

 

Could you please explain your request more detailed?

 

Best regards,

Kostiantyn Diachenko. 

Kostiantyn Diachenko, Community Advisor, Certified Senior AEM Developer, creator of free AEM VLT Tool, maintainer of AEM Tools plugin.
VodjakxaAuthor
Level 2
February 12, 2025

I have AEM 6.5. Yes, you understood correctly. I have to do it with a job.

konstantyn_diachenko
Community Advisor
konstantyn_diachenkoCommunity AdvisorAccepted solution
Community Advisor
February 12, 2025

1. OSGi Service to Process Content Fragment and Save JSON as DAM Asset
This service reads properties from a Content Fragment, converts them to JSON, and uploads the JSON as an asset in the DAM.

@8220494(service = ServiceA.class, immediate = true) public class ServiceA { private static final Logger LOG = LoggerFactory.getLogger(ServiceA.class); private static final String DAM_JSON_PATH = "/content/dam/generated-json/"; @3214626 private ResourceResolverFactory resourceResolverFactory; /** * Converts a Content Fragment to JSON and saves it as an asset in DAM */ public void processContentFragment(String contentFragmentPath) { try (ResourceResolver resolver = getServiceResourceResolver()) { Resource cfResource = resolver.getResource(contentFragmentPath); if (cfResource == null) { LOG.error("Content Fragment not found at: {}", contentFragmentPath); return; } ContentFragment contentFragment = cfResource.adaptTo(ContentFragment.class); if (contentFragment == null) { LOG.error("Invalid Content Fragment at path: {}", contentFragmentPath); return; } String jsonContent = convertContentFragmentToJson(contentFragment); saveJsonAsDamAsset(resolver, jsonContent, contentFragmentPath); } catch (Exception e) { LOG.error("Error processing Content Fragment: {}", e.getMessage(), e); } } /** * Converts Content Fragment to JSON */ private String convertContentFragmentToJson(ContentFragment contentFragment) throws IOException { Map<String, Object> data = new HashMap<>(); contentFragment.getElements().forEachRemaining(element -> data.put(element.getName(), element.getValue().getValue())); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.writeValueAsString(data); } /** * Saves JSON as a DAM asset */ private void saveJsonAsDamAsset(ResourceResolver resolver, String jsonContent, String contentFragmentPath) throws IOException { AssetManager assetManager = resolver.adaptTo(AssetManager.class); if (assetManager == null) { LOG.error("Could not adapt to AssetManager."); return; } String jsonAssetPath = DAM_JSON_PATH + getJsonFileName(contentFragmentPath); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(jsonContent.getBytes())) { Asset asset = assetManager.createAsset(jsonAssetPath, inputStream, "application/json", true); if (asset != null) { LOG.info("JSON asset created at {}", jsonAssetPath); } } } /** * Generate a unique JSON file name */ private String getJsonFileName(String contentFragmentPath) { return contentFragmentPath.replace("/content/dam/", "").replace("/", "_") + ".json"; } /** * Get service user resource resolver */ private ResourceResolver getServiceResourceResolver() throws LoginException { Map<String, Object> params = new HashMap<>(); params.put(ResourceResolverFactory.SUBSERVICE, "content-fragment-service"); return resourceResolverFactory.getServiceResourceResolver(params); } }

 2. Sling Job to Execute the Service
A Sling Job will call the above service to process Content Fragments.

@8220494( service = JobConsumer.class, property = { JobConsumer.PROPERTY_TOPICS + "=com/example/jobs/processContentFragment" } ) public class ContentFragmentJob implements JobConsumer { private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentJob.class); @3214626 private ContentFragmentToJsonService contentFragmentToJsonService; @9944223 public JobResult process(Job job) { String contentFragmentPath = job.getProperty("contentFragmentPath", String.class); if (contentFragmentPath == null) { LOG.error("Content Fragment path not provided in job."); return JobResult.FAILED; } LOG.info("Processing Content Fragment: {}", contentFragmentPath); contentFragmentToJsonService.processContentFragment(contentFragmentPath); return JobResult.OK; } }

 3. How to Trigger the Sling Job

A Sling Job can be manually triggered from the Java code, or via a scheduler, workflow, or event listener.

@8220494(service = ContentFragmentJobTrigger.class) public class ContentFragmentJobTrigger { private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentJobTrigger.class); private static final String JOB_TOPIC = "com/example/jobs/processContentFragment"; @3214626 private JobManager jobManager; public void triggerJob(String contentFragmentPath) { Map<String, Object> jobProperties = new HashMap<>(); jobProperties.put("contentFragmentPath", contentFragmentPath); jobManager.addJob(JOB_TOPIC, jobProperties); LOG.info("Job triggered for Content Fragment: {}", contentFragmentPath); } }

 

However, I would also consider another approach with servlet that will be mapped to some selector. It will allow you to request content fragment path with selector and json extension and get required data without persisting it. For example: /content/dam/cfs/my-cf.consumer-1.json. 

This is because AssetManager.createAsset is working in AEM on prem, but it's deprecated in AEMaaCS. 

 

Best regards,

Kostiantyn Diachenko. 

Kostiantyn Diachenko, Community Advisor, Certified Senior AEM Developer, creator of free AEM VLT Tool, maintainer of AEM Tools plugin.