AEM 6.5.12.0 - InDesign Server Connector for creating PDF using Templates and Content Fragments

Goal

Using this simple InDesign Server Connector module (deployed on Author or Publish) a user can Create PDFs using InDesign Templates and content entered as Raw Text or Content Fragments

Demo | Package Install | InDesign Template | Github


Connector Design


InDesign Template


Connector Configuration

                       http://localhost:4502/system/console/configMgr/apps.experienceaem.assets.core.services.impl.IDSServiceImpl



Get Template Structure (for content entry form)

                       http://localhost:4502/content/dam/experience-aem/weretail-brochure.indd.getTemplateStructure


Content for PDF as Raw Text



Content for PDF as Content Fragment





Solution

1) Create a servlet apps.experienceaem.assets.core.servlets.IDSRequestServlet to handle PDF processing requests. when POSTed with createPDF selector (eg. http://localhost:4502/content/dam/experience-aem/weretail-brochure.indd.createPDF) on a template and content set in request body, logic creates sling job item com/eaem/ids for InDesign Server communication. Requests are processed in order received, one at a time.

package apps.experienceaem.assets.core.servlets;

import com.adobe.cq.dam.cfm.ContentElement;
import com.adobe.cq.dam.cfm.ContentFragment;
import com.adobe.cq.dam.cfm.FragmentData;
import com.adobe.xfa.ut.StringUtils;
import com.day.cq.commons.TidyJSONWriter;
import com.day.cq.commons.jcr.JcrUtil;
import com.google.gson.JsonObject;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
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.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.JobManager;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.Session;
import javax.servlet.Servlet;
import java.text.SimpleDateFormat;
import java.util.*;

import static apps.experienceaem.assets.core.util.Constants.*;

@Component(
immediate = true,
service = Servlet.class,
property = {
Constants.SERVICE_DESCRIPTION + "=Experience AEM InDesign Server Process Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_GET,
"sling.servlet.methods=" + HttpConstants.METHOD_POST,
"sling.servlet.resourceTypes=sling/servlet/default",
"sling.servlet.extensions=" + "createPDF"
}
)
public class IDSRequestServlet extends SlingAllMethodsServlet {
private final Logger logger = LoggerFactory.getLogger(getClass());

private final SimpleDateFormat FOLDER_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

@Reference
private JobManager jobManager;

@Reference
private ResourceResolverFactory resolverFactory;

@Override
protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) {
resp.setContentType("application/json");

final Resource resource = req.getResource();

try {
TidyJSONWriter writer = new TidyJSONWriter(resp.getWriter());
writer.object();

if (resource == null) {
writer.key("error").value("No resource found");
writer.endObject();
}

ResourceResolver resolver = resolverFactory.getServiceResourceResolver(INDESIGN_AUTH_INFO);
Session session = resolver.adaptTo(Session.class);

Node jobNode = createJobNode(resolver, resource.getPath());

HashMap<String, Object> jobProps = new HashMap<String, Object>();
jobProps.put(INDESIGN_TEMPLATE_PATH, resource.getPath());
jobProps.put(JOB_PATH, jobNode.getPath());
jobProps.put(CONTENT_JSON, getStructuredContentAsJsonString(req, resolver));

Job job = jobManager.addJob(INDESIGN_SERVER_TOPIC, jobProps);

jobNode.setProperty("jobId", job.getId());

session.save();

writer.key("success").value(jobNode.getPath());
writer.endObject();
} catch (Exception e) {
logger.error("Error scheduling indesign server job for asset : ", resource.getPath());
}
}

@Override
protected void doPost(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) {
doGet(req, resp);
}

private String getStructuredContentAsJsonString(SlingHttpServletRequest req, ResourceResolver resolver) {
JsonObject contentMap = new JsonObject();
JsonObject valueJson = null;

boolean preview = false;

if(!StringUtils.isEmpty(req.getParameter(PARAM_PREVIEW))){
preview = Boolean.valueOf(req.getParameter(PARAM_PREVIEW));
}

int index = 1;
String paramPath, paramType, paramValue;

do {
paramPath = req.getParameter(PARAM_PREFIX + index + PARAM_PATH);

if (StringUtils.isEmpty(paramPath)) {
break;
}

paramPath = paramPath.substring(paramPath.lastIndexOf("/") + 1);

valueJson = new JsonObject();

paramType = req.getParameter(PARAM_PREFIX + index + PARAM_TYPE);

paramType = !StringUtils.isEmpty(paramType) ? paramType : RAW_TEXT;

paramValue = req.getParameter(PARAM_PREFIX + index + PARAM_VALUE);

if(paramType.equals(CF_PATH)){
addValuesFromCF(resolver, contentMap, paramPath, paramValue);
}else{
valueJson.addProperty("type", paramType);
paramValue = !StringUtils.isEmpty(paramValue) ? paramValue : "";

if(paramType.equals(JCR_PATH) && preview){
paramValue = paramValue + PREVIEW_RENDITION;
}

valueJson.addProperty("value", paramValue);
contentMap.add(paramPath, valueJson);
}

index = index + 1;
} while (true);

return contentMap.toString();
}

private void addValuesFromCF(ResourceResolver resolver, JsonObject contentMap, String idPathPrefix, String cfPath){
Resource cfResource = resolver.getResource(cfPath);

if(cfResource == null){
return;
}

JsonObject valueJson = null; String value = null;
ContentFragment cf = cfResource.adaptTo(ContentFragment.class);

Iterator<ContentElement> cfElementsItr = cf.getElements();

while(cfElementsItr.hasNext()) {
ContentElement cfElement = cfElementsItr.next();

if (cfElement == null) {
continue;
}

FragmentData fragValue = getVariationValue(cfElement, MASTER_VARIATION);

if(fragValue == null){
continue;
}

valueJson = new JsonObject();

value = String.valueOf(fragValue.getValue()).trim();

if(value.startsWith("/")){
valueJson.addProperty("type", JCR_PATH);
}else{
valueJson.addProperty("type", RAW_TEXT);
}

valueJson.addProperty("value", removeUnnecessaryChars(value));

contentMap.add(idPathPrefix + cfElement.getName(), valueJson);
}
}

private String removeUnnecessaryChars(String value){
if(StringUtils.isEmpty(value) || value.equals("null")){
return "";
}

if(value.startsWith(P_TAG)){
value = value.substring(P_TAG.length(), value.lastIndexOf(P_END_TAG));
}

return value;
}

private FragmentData getVariationValue(ContentElement cfElement, String variation){
if(StringUtils.isEmpty(variation) || "master".equals(variation)){
return cfElement.getValue();
}

return cfElement.getVariation(variation).getValue();
}

private Node createJobNode(ResourceResolver resolver, String indesignTemplatePath) throws Exception {
Resource reportRes = resolver.getResource(INDESIGN_GEN_REPORTS_PATH);
Node reportNode = null;

if (reportRes == null) {
JcrUtil.createPath(INDESIGN_GEN_REPORTS_PATH, "sling:Folder", "sling:Folder", resolver.adaptTo(Session.class), false);
}

reportNode = JcrUtil.createPath(INDESIGN_GEN_REPORTS_PATH + "/" + FOLDER_FORMAT.format(new Date()),
"sling:Folder", "sling:Folder", resolver.adaptTo(Session.class), true);

Calendar createTime = Calendar.getInstance();
createTime.setTimeInMillis(createTime.getTimeInMillis());

String jobNodeName = UUID.randomUUID().toString();
Node jobNode = reportNode.addNode(jobNodeName.replaceAll("/", "-"), "nt:unstructured");

jobNode.setProperty(INDESIGN_TEMPLATE_PATH, indesignTemplatePath);
jobNode.setProperty("jobStatus", JOB_STATUS_PROCESSING);
jobNode.setProperty("jcr:created", createTime);

return jobNode;
}
}

2) Create a Sling Job Consumer apps.experienceaem.assets.core.listeners.IDSJobConsumer for assembling the necessary SOAP payload (PDF creation scripts and content for IDS template) send a request to InDesign Server running on 8080 (> InDesignServer.com -port 8080)

package apps.experienceaem.assets.core.listeners;

import apps.experienceaem.assets.core.services.IDSService;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.lang.StringUtils;
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.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import java.util.HashMap;
import java.util.Map;

import static apps.experienceaem.assets.core.util.Constants.*;

@Component(
immediate = true,
service = JobConsumer.class,
property = {
"job.topics=" + INDESIGN_SERVER_TOPIC,
}
)
public class IDSJobConsumer implements JobConsumer {
protected final Logger logger = LoggerFactory.getLogger(IDSJobConsumer.class);

@Reference
private ResourceResolverFactory resolverFactory;

@Reference
private IDSService idsService;

public JobResult process(Job job) {
ResourceResolver resolver = null;

String indesignTemplatePath = (String)job.getProperty(INDESIGN_TEMPLATE_PATH);

try {
resolver = resolverFactory.getServiceResourceResolver(INDESIGN_AUTH_INFO);

String exportStructure = (String)job.getProperty(EXPORT_STRUCTURE);

if(StringUtils.isNotEmpty(exportStructure)){
return executeStructureExport(indesignTemplatePath, resolver);
}else{
return executePDFExport(job, resolver);
}
} catch (Exception e) {
logger.error("Failed to process indesign server job for asset {} ", indesignTemplatePath, e);
return JobResult.FAILED;
} finally {
if(resolver != null){
resolver.close();
}
}
}

private String[] getIDSScriptForStructure(){
return new String[] { "/libs/settings/dam/indesign/scripts/json2.jsx/jcr:content",
"/libs/settings/dam/indesign/scripts/cq-lib.jsx/jcr:content",
"/apps/eaem-assets-ids-connector/indesign/scripts/export-structure.jsx/jcr:content"};
}

private JobResult executeStructureExport(String indesignTemplatePath, ResourceResolver resolver )
throws Exception{
Resource indesignRes = resolver.getResource(indesignTemplatePath);

if(indesignRes == null){
logger.error("File not found {} ", indesignTemplatePath);
return JobResult.FAILED;
}

Map<String, String> scriptArs = new HashMap<String, String>();
scriptArs.put("resourcePath", indesignTemplatePath);

String payload = idsService.buildSOAPPayload(resolver, scriptArs, indesignRes, getIDSScriptForStructure());

JsonObject responseObj = idsService.executeInDesignServerRequest(resolver, payload);

JsonElement structureJSON = responseObj.get("structure");

if(structureJSON == null){
JsonElement indesignError = responseObj.get("error");

logger.error("Indesign server job resulted in error for asset {} {} ", indesignTemplatePath, indesignError);

return JobResult.FAILED;
}

Resource metadataRes = indesignRes.getChild("jcr:content/metadata");

metadataRes.adaptTo(Node.class).setProperty(STRUCTURE_JSON, structureJSON.toString());

resolver.commit();

return JobResult.OK;
}

private JobResult executePDFExport(Job job, ResourceResolver resolver) throws Exception{
String indesignTemplatePath = (String)job.getProperty(INDESIGN_TEMPLATE_PATH);
Resource indesignRes = resolver.getResource(indesignTemplatePath);

String jobReportPath = (String)job.getProperty(JOB_PATH);
Resource jobReportRes = resolver.getResource(jobReportPath);
Node jobReportNode = jobReportRes.adaptTo(Node.class);

if(indesignRes == null){
logger.error("File not found {} ", indesignTemplatePath);
jobReportNode.setProperty("jobStatus", "File not found : " + indesignTemplatePath);

resolver.commit();
return JobResult.FAILED;
}

Map<String, String> scriptArs = new HashMap<String, String>();
scriptArs.put("resourcePath", indesignTemplatePath);
scriptArs.put("aemUploadPath", jobReportNode.getPath());
scriptArs.put(CONTENT_JSON, (String)job.getProperty(CONTENT_JSON));

String payload = idsService.buildSOAPPayload(resolver, scriptArs, indesignRes, null);

JsonObject responseObj = idsService.executeInDesignServerRequest(resolver, payload);

JsonElement indesignSuccess = responseObj.get("success");

if(indesignSuccess == null){
JsonElement indesignError = responseObj.get("error");

if(indesignError != null){
logger.error("Indesign server job resulted in error for asset {} {} ", indesignTemplatePath, indesignError.toString());
jobReportNode.setProperty("jobStatus", indesignError.toString());
}else{
jobReportNode.setProperty("jobStatus", "Error processing document, check indesign console log");
}

resolver.commit();

return JobResult.FAILED;
}

resolver.commit();

//idsService.uploadToS3(jobReportRes.getChildren().iterator().next());

jobReportNode.setProperty("jobStatus",JOB_STATUS_SUCCESS);

resolver.commit();

return JobResult.OK;
}
}

3) Create a OSGI service apps.experienceaem.assets.core.services.impl.IDSServiceImpl for configuration and helper methods to create request payload for InDesign Server...

package apps.experienceaem.assets.core.services.impl;

import apps.experienceaem.assets.core.listeners.IDSJobConsumer;
import apps.experienceaem.assets.core.services.IDSService;
import com.day.cq.dam.commons.xml.DocumentBuilderFactoryProvider;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.osgi.services.HttpClientBuilderFactory;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
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 org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import javax.jcr.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.util.Arrays;
import java.util.Map;

@Component(service = IDSService.class)
@Designate(ocd = IDSServiceImpl.IDSConfiguration.class)
public class IDSServiceImpl implements IDSService{
private final Logger logger = LoggerFactory.getLogger(IDSJobConsumer.class);

private String[] idsScripts = new String[0];
private String inDesignServerUrl = "";
private String base64EncodedAEMCreds = "";
private String aemHost = "";
private String s3BucketName = "";
private String s3AccessKey = "";
private String s3SecretKey = "";
private String s3Region = "";

@Reference
private transient HttpClientBuilderFactory httpClientBuilderFactory;

private transient CloseableHttpClient httpClient;

@Override
public JsonObject executeInDesignServerRequest(ResourceResolver resolver, String payload) throws Exception{
String response = Request.Post(inDesignServerUrl)
.addHeader("HttpPost", "")
.bodyString(payload, ContentType.APPLICATION_XML)
.execute().returnContent().asString();

logger.debug("InDesign Server Response : " + response);

Document document = getResponseDocument(response);

String resultJSON = document.getElementsByTagName("data").item(0).getFirstChild().getNodeValue();

JsonObject resultObj = new JsonParser().parse(resultJSON).getAsJsonObject();

return resultObj;
}

private Document getResponseDocument(String responseStr) throws Exception{
DocumentBuilderFactoryProvider factoryprovider = new DocumentBuilderFactoryProvider();
DocumentBuilderFactory factory = factoryprovider.createSecureBuilderFactory(false, false);

DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
logger.debug("Error parsing SOAP response {}:", exception.getMessage());
}
@Override
public void error(SAXParseException exception) throws SAXException {
logger.debug("Error parsing SOAP response {}:", exception.getMessage());
}

@Override
public void fatalError(SAXParseException exception) throws SAXException {
logger.debug("Error parsing SOAP response {}:", exception.getMessage());
}
});

return builder.parse(new InputSource(new StringReader(responseStr)));
}

@Override
public String buildSOAPPayload(ResourceResolver resolver, Map<String, String> scriptArs,
Resource indesignRes, String[] customScripts){
StringBuilder payload = new StringBuilder();

payload.append(getSOAPHeader());

payload.append("<SOAP-ENV:Body><IDSP:RunScript><IDSP:runScriptParameters><IDSP:scriptText><![CDATA[");

payload.append(getGiantScript(resolver, customScripts));

payload.append("]]></IDSP:scriptText>");

payload.append(getScriptInputArgs(scriptArs, indesignRes));

payload.append("</IDSP:runScriptParameters></IDSP:RunScript></SOAP-ENV:Body>");

payload.append(getSOAPFooter());

return payload.toString();
}

private String getScriptInputArgs(Map<String, String> scriptArs, Resource indesignRes){
scriptArs.put("aemHost", aemHost);
scriptArs.put("base64EncodedAEMCreds", base64EncodedAEMCreds);

StringBuilder args = new StringBuilder();
args.append("<IDSP:scriptLanguage>javascript</IDSP:scriptLanguage>");

scriptArs.entrySet().forEach(entry -> {
args.append("<IDSP:scriptArgs>");
args.append("<IDSP:name>").append(entry.getKey()).append("</IDSP:name>");
args.append("<IDSP:value><![CDATA[").append(entry.getValue()).append("]]></IDSP:value>");
args.append("</IDSP:scriptArgs>");
});

return args.toString();
}

private String getSOAPHeader(){
return "<?xml version='1.0' encoding='UTF-8'?>" +
"<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " +
"xmlns:xsd='http://www.w3.org/2001/XMLSchema' " +
"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " +
"xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/' " +
"xmlns:IDSP='http://ns.adobe.com/InDesign/soap/'>";
}

private String getSOAPFooter(){
return "</SOAP-ENV:Envelope>";
}

private String getGiantScript(ResourceResolver resolver, String[] customScripts){
StringBuilder script = new StringBuilder();

if(ArrayUtils.isEmpty(customScripts)){
customScripts = idsScripts;
}

Arrays.stream(customScripts).forEach( scriptPath -> {
Resource resource = resolver.getResource(scriptPath);

if(resource == null){
throw new RuntimeException("Error finding script resource : " + scriptPath);
}

Node scriptNode = (Node)resource.adaptTo(Node.class);
try {
script.append(IOUtils.toString(scriptNode.getProperty("jcr:data").getBinary().getStream()));
} catch (Exception e) {
throw new RuntimeException("Error adding script resource : " + scriptPath);
}
});

return script.toString();
}

@Activate
@Modified
protected void activate(final IDSConfiguration config) {
idsScripts = config.inDesignServerScripts();

inDesignServerUrl = config.inDesignServerUrl();
aemHost = config.aemHost();
base64EncodedAEMCreds = config.base64EncodedAEMCreds();

final HttpClientBuilder builder = httpClientBuilderFactory.newBuilder();

final RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000)
.setSocketTimeout(30000).build();

builder.setDefaultRequestConfig(requestConfig);

httpClient = builder.build();
}

@ObjectClassDefinition(name = "Experience AEM InDesign Server Configuration")
public @interface IDSConfiguration {

@AttributeDefinition(
name = "InDesign Scripts in order",
description = "Add the InDesign Server Scripts in execution order",
type = AttributeType.STRING,
cardinality = 5
)
String[] inDesignServerScripts() default {
"/libs/settings/dam/indesign/scripts/json2.jsx/jcr:content",
"/libs/settings/dam/indesign/scripts/cq-lib.jsx/jcr:content",
"/apps/eaem-assets-ids-connector/indesign/scripts/create-pdf.jsx/jcr:content"
};

@AttributeDefinition(
name = "InDesign Server endpoint",
description = "Add the InDesign Server endpoint url eg. http://localhost:8080",
type = AttributeType.STRING
)
String inDesignServerUrl() default "http://localhost:8080";

@AttributeDefinition(
name = "AEM Server",
description = "The AEM Server, InDesign Server should connect to and download the documents/images/fragments",
type = AttributeType.STRING
)
String aemHost() default "localhost:4502";

@AttributeDefinition(
name = "Base64 encoded AEM Creds",
description = "Base 64 encoded AEM Credentials Indesign server should use for download, eg. admin:admin is YWRtaW46YWRtaW4=",
type = AttributeType.STRING
)
String base64EncodedAEMCreds() default "YWRtaW46YWRtaW4=";
}
}

4) Add the script /apps/eaem-assets-ids-connector/indesign/scripts/export-structure.jsx for exporting the ID template structure. This JSON array exported can be used in  form dropdowns to enter content required for PDF....

http://localhost:4502/content/dam/experience-aem/weretail-brochure.indd.getTemplateStructure

(function () {
var returnObj = {}, aemHost, base64EncodedAEMCreds, resourcePath, document;

function setParamsFromScriptArgs(){
if (app.scriptArgs.isDefined("base64EncodedAEMCreds")) {
base64EncodedAEMCreds = app.scriptArgs.getValue("base64EncodedAEMCreds");
} else {
throw "AEM host credentials argument is missing";
}

if (app.scriptArgs.isDefined("aemHost")) {
aemHost = app.scriptArgs.getValue("aemHost");
} else {
throw "aemHost argument is missing";
}

if (app.scriptArgs.isDefined("resourcePath")) {
resourcePath = app.scriptArgs.getValue("resourcePath");
} else {
throw "resourcePath argument missing";
}

app.consoleout('base64EncodedAEMCreds --- ' + base64EncodedAEMCreds);
app.consoleout('aemHost --- ' + aemHost);
app.consoleout('resourcePath --- ' + resourcePath);
}

function exportStructureJSON(){
var sourceFolder = getSourceFolder(),
fileName = resourcePath.substring(resourcePath.lastIndexOf ('/') + 1),
xmlFile = new File( sourceFolder.fullName + "/" + fileName + ".xml"),
sourceFile = new File(sourceFolder.fullName + "/" + fileName);

app.consoleout('Fetching resource from AEM: ' + aemHost + resourcePath + ' to ' + sourceFile);

fetchResource (aemHost, base64EncodedAEMCreds, resourcePath, sourceFile);

app.consoleout('Exporting structure for - ' + sourceFile);

var document = app.open(sourceFile);

document.exportFile(ExportFormat.xml, xmlFile);

xmlFile.open('r');

var xmlContent = xmlFile.read();

xmlFile.close();

var structureXML = new XML (xmlContent),
structureJSON = [], parentPath,
eles = structureXML.elements(), element, eleName;

for(var x = 0 ; x < eles.length(); x++){
element = eles.child(x);

if(!parentPath){
parentPath = "/" + element.parent().name() + "/";
}

structureJSON.push(parentPath + element.name());
}

return structureJSON;
}

function getSourceFolder(){
var today = new Date(),
folderName = today.getFullYear() + "-" + today.getMonth() + "-" + today.getDate() + "-" + today.getHours()
+ "-" + today.getMinutes() + "-" + today.getSeconds();

var sourceFolder = new Folder(folderName);
sourceFolder.create();

return sourceFolder;
}

try{
setParamsFromScriptArgs();

returnObj.structure = exportStructureJSON();
}catch(err){
returnObj.error = err;
app.consoleout("Error processing document structure : " + resourcePath + ", error : " + err);
}finally{
if(document){
document.close(SaveOptions.no);
}
}

return JSON.stringify(returnObj);
}());

5) Add the script /apps/eaem-assets-ids-connector/indesign/scripts/create-pdf.jsx executed on InDesign Server to process the content payload received from AEM and create PDF

(function () {
var returnObj = {}, aemHost, base64EncodedAEMCreds, resourcePath, document,
aemUploadPath, contentJson;

function createPDF() {
var sourceFolder = getSourceFolder(),
fileName = resourcePath.substring(resourcePath.lastIndexOf ('/') + 1),
xmlFile = new File( sourceFolder.fullName + "/" + fileName + ".xml"),
sourceFile = new File(sourceFolder.fullName + "/" + fileName);

with (app.pdfExportPreferences) {
viewDocumentAfterExport = false;
pageRange = PageRange.ALL_PAGES;
}

app.consoleout('Fetching resource from AEM: ' + aemHost + resourcePath + ' to ' + sourceFile);

fetchResource (aemHost, base64EncodedAEMCreds, resourcePath, sourceFile);

var pdfOutputFile = new File(sourceFolder.fullName + "/" + fileName + '.pdf');

app.consoleout('Started PDF export - ' + pdfOutputFile);

if(contentJson){
document = app.open(sourceFile);

document.exportFile(ExportFormat.xml, xmlFile);

xmlFile.open('r');

var xmlContent = xmlFile.read();

xmlFile.close();

var structureXML = new XML (xmlContent),
eles = structureXML.elements(), element, eleName, data;

for(var x = 0 ; x < eles.length(); x++){
element = eles.child(x);
eleName = element.name();
data = contentJson[eleName];

if(data){
if(data.type === "JCR_PATH"){
var jcrName = data.value.substring(data.value.lastIndexOf ('/') + 1);

if(jcrName.indexOf("cq5dam.") == 0){
jcrName = data.value.substring(0, data.value.lastIndexOf ('/jcr:content/renditions'));
jcrName = jcrName.substring(jcrName.lastIndexOf ('/') + 1);
}

var jcrFile = new File(sourceFolder.fullName + "/" + jcrName);

app.consoleout('Fetching resource : ' + data.value + ' to ' + jcrFile);

fetchResource (aemHost, base64EncodedAEMCreds, data.value, jcrFile);

structureXML[eleName].@href = "file://./" + jcrName;
}else{
structureXML[eleName] = data.value;
}
}else{
delete structureXML[eleName];
}
}

xmlFile.encoding = "UTF8";

xmlFile.open("w");

xmlContent = structureXML.toString();

xmlFile.write(xmlContent);

xmlFile.close();

document.importXML(xmlFile);
}

document.exportFile(ExportFormat.pdfType, pdfOutputFile);

app.consoleout('Uploading PDF to - ' + aemUploadPath);

putResource(aemHost, base64EncodedAEMCreds, pdfOutputFile, pdfOutputFile.name, 'application/pdf', aemUploadPath);

sourceFolder.remove();

app.consoleout('PDF export complete...');

returnObj.success = "completed";
}

function getSourceFolder(){
var today = new Date(),
folderName = today.getFullYear() + "-" + today.getMonth() + "-" + today.getDate() + "-" + today.getHours()
+ "-" + today.getMinutes() + "-" + today.getSeconds();

var sourceFolder = new Folder(folderName);
sourceFolder.create();

return sourceFolder;
}

function setParamsFromScriptArgs(){
if (app.scriptArgs.isDefined("base64EncodedAEMCreds")) {
base64EncodedAEMCreds = app.scriptArgs.getValue("base64EncodedAEMCreds");
} else {
throw "AEM host credentials argument is missing";
}

if (app.scriptArgs.isDefined("aemHost")) {
aemHost = app.scriptArgs.getValue("aemHost");
} else {
throw "aemHost argument is missing";
}

if (app.scriptArgs.isDefined("resourcePath")) {
resourcePath = app.scriptArgs.getValue("resourcePath");
} else {
throw "resourcePath argument missing";
}

if (app.scriptArgs.isDefined("contentJson")) {
contentJson = JSON.parse(app.scriptArgs.getValue("contentJson"));
app.consoleout('contentJson: ' + app.scriptArgs.getValue("contentJson"));
} else {
throw "contentJson argument missing";
}

aemUploadPath = app.scriptArgs.getValue("aemUploadPath");

app.consoleout('base64EncodedAEMCreds --- ' + base64EncodedAEMCreds);
app.consoleout('aemHost --- ' + aemHost);
app.consoleout('resourcePath --- ' + resourcePath);
app.consoleout('aemUploadPath --- ' + aemUploadPath);
}

try{
setParamsFromScriptArgs();

//setTestParams();

createPDF();
}catch(err){
returnObj.error = err;
app.consoleout("Error processing document : " + resourcePath + ", error : " + err);
}finally{
if(document){
document.close(SaveOptions.no);
}
}

return JSON.stringify(returnObj);
}());

6) Add /apps/eaem-assets-ids-connector/osgiconfig/config/org.apache.sling.event.jobs.QueueConfiguration-eaem-ids with following properties for ordering the com/eaem/ids sling job queue IDS requests...

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
queue.maxparallel="{Long}1"
queue.name="Experience AEM InDesign Server Processing Queue"
queue.priority="MIN"
queue.retries="{Long}0"
queue.retrydelay="{Long}60000"
queue.topics="com/eaem/ids"
queue.type="ORDERED"/>

7)  Add repoinit script in /apps/eaem-assets-ids-connector/osgiconfig/config/org.apache.sling.jcr.repoinit.RepositoryInitializer-eaem-ids.config for  creating a service user eaem-ids-service and specifying ACLs 

scripts=[
"
create service user eaem-ids-service with path system/experience-aem
set ACL for eaem-ids-service
allow jcr:read on /apps
allow jcr:read on /conf
allow jcr:read on /libs
allow jcr:all on /content
allow jcr:read on /var
allow jcr:all on /var/dam
end
"
]

8) Add core bundle to service user mapping in /apps/eaem-assets-ids-connector/osgiconfig/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-eaem-ids.cfg.json

{
"user.mapping": [
"eaem-assets-ids-connector.core:eaem-ids-service=[eaem-ids-service]"
]
}

No comments:

Post a Comment