
com.adobe.aemds.guide.utils.GuideUtils Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2014 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.aemds.guide.utils;
import com.adobe.aemds.guide.common.GuideContainer;
import com.adobe.aemds.guide.common.GuideNode;
import com.adobe.aemds.guide.common.GuidePanel;
import com.adobe.aemds.guide.fdinternal.utils.JsonResourceWriter;
import com.adobe.aemds.guide.model.TextVariable;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.aemds.guide.service.GuideLocalizationService;
import com.adobe.aemds.guide.service.GuideModelImporter;
import com.adobe.aemds.guide.service.GuideModelTransformer;
import com.adobe.aemds.guide.service.GuideModuleImporter;
import com.adobe.aemds.guide.service.GuideSchemaType;
import com.adobe.aemds.guide.submitutils.FileRequestParameter;
import com.adobe.aemds.guide.themes.GuideThemeConstants;
import com.adobe.forms.common.service.FileAttachmentWrapper;
import com.adobe.forms.common.service.StaleAssetIndicatorService;
import com.adobe.forms.common.submitutils.CustomParameterRequest;
import com.adobe.forms.common.submitutils.CustomResponse;
import com.adobe.forms.common.submitutils.ParameterMap;
import com.adobe.granite.resourceresolverhelper.ResourceResolverHelper;
import com.adobe.granite.ui.clientlibs.ClientLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.adobe.granite.ui.clientlibs.LibraryType;
import com.adobe.granite.ui.components.ds.ValueMapResource;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.analytics.testandtarget.util.Constants;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.Template;
import com.day.cq.wcm.api.TemplatedResource;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.api.components.ComponentManager;
import com.day.cq.wcm.api.components.EditConfig;
import com.day.cq.wcm.api.components.EditContext;
import com.day.cq.wcm.api.components.Toolbar;
import com.day.cq.wcm.commons.WCMUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.http.HttpHeaders;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.vault.util.Text;
import org.apache.sling.api.SlingException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.request.RequestParameterMap;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.NonExistingResource;
import org.apache.sling.api.resource.PersistenceException;
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.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.i18n.ResourceBundleProvider;
import org.apache.sling.servlets.post.Modification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.script.SimpleBindings;
import javax.servlet.RequestDispatcher;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URLDecoder;
import java.security.Principal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GuideUtils {
private static Logger logger = LoggerFactory.getLogger(GuideUtils.class);
private static final String MSG_NO_REPEATABLE_ITEM = "Could not compute repeatable item for chart.";
private final static Map nodeClassToResourceTypeMap = new HashMap<>();
static {
nodeClassToResourceTypeMap.put(GuideConstants.ROOTPANEL_NODECLASS, GuideConstants.RT_ROOT_PANEL);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDECONTAINER_NODECLASS, GuideConstants.RT_GUIDECONTAINER);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_PANEL, GuideConstants.RT_PANEL);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_BUTTON, GuideConstants.RT_GUIDEBUTTON);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_CHART, GuideConstants.RT_GUIDECHART);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_CHECKBOX, GuideConstants.RT_GUIDECHECKBOX);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_DATEPICKER, GuideConstants.RT_GUIDEDATEPICKER);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_DROPDOWNLIST, GuideConstants.RT_GUIDEDROPDOWNLIST);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_EMAIL, GuideConstants.RT_GUIDEEMAIL);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_FILEUPLOAD, GuideConstants.RT_GUIDEFILEUPLOAD);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_IMAGE, GuideConstants.RT_GUIDEDRAWIMAGE);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_IMAGECHOICE, GuideConstants.RT_GUIDEIMAGECHOICE);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD, GuideConstants.RT_GUIDEFIELD);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_NUMERICBOX, GuideConstants.RT_GUIDENUMERICBOX);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_PASSWORDBOX, GuideConstants.RT_GUIDEPASSWORDBOX);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_RADIOBUTTON, GuideConstants.RT_GUIDERADIOBUTTON);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_SCRIBBLE, GuideConstants.RT_GUIDESCRIBBLE);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_SWITCH, GuideConstants.RT_GUIDESWITCH);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_TEXTBOX, GuideConstants.RT_GUIDETEXTBOX);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_TELEPHONE, GuideConstants.RT_GUIDETELEPHONE);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_TERMSANDCONDITIONS, GuideConstants.RT_GUIDETERMSANDCONDITIONS);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_FIELD_TEXTDRAW, GuideConstants.RT_GUIDEDRAWTEXT);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_TABLE, GuideConstants.RT_TABLE);
nodeClassToResourceTypeMap.put(GuideConstants.GUIDE_TABLE_ROW, GuideConstants.RT_TABLE_ROW);
}
/**
* Generic utility to get adobe sign configuration path.
*
* @param guideContainerResource - resource representing guide container of the form
* @return String - adobe sign configured path if present
* @pad.exclude Exclude from Published API.
*/
public static String getSignConfigPath(Resource guideContainerResource) {
if (guideContainerResource == null) {
return null;
}
String signConfigPath = null;
ValueMap guideContainerProperties = guideContainerResource.getValueMap();
String useSignedPdf = guideContainerProperties.get("_useSignedPdf", "");
if (StringUtils.equals("true", useSignedPdf)) {
Resource signerInfo = guideContainerResource.getChild("signerInfo");
ValueMap signerInfoProperties = signerInfo.getValueMap();
signConfigPath = signerInfoProperties.get("signConfigPath", "");
} else {
// check if legacy adobe sign is being used
String query = "/jcr:root" + guideContainerResource.getPath() + "//element(*, nt:unstructured)[@guideNodeClass = 'esign']";
Iterator iterator = guideContainerResource.getResourceResolver().findResources(query, "xpath");
while (iterator.hasNext()) {
Resource esignResource = iterator.next();
ValueMap esignProperties = esignResource.getValueMap();
signConfigPath = esignProperties.get("cq:cloudserviceconfigs", "");
break;
}
}
return signConfigPath;
}
/**
* Generic utility to parse adobe sign fields from HTML
*
* @param htmlVal - html string having adobe sign text tags
* @return JSONArray - array of names of adobe sign fields
* @pad.exclude Exclude from Published API.
*/
public static JSONArray getAdobeSignFields(String htmlVal) {
JSONArray adobeSignFieldsArray = new JSONArray();
HashSet hs = new HashSet();
Pattern pattern = Pattern.compile("\\{\\{[*]?([^:]*)_es_:");
Matcher matcher = pattern.matcher(htmlVal);
while (matcher.find()) {
String fieldName = matcher.group(1);
if (hs.add(fieldName)) {
adobeSignFieldsArray.put(fieldName);
}
}
return adobeSignFieldsArray;
}
/**
* Generic utility to get Text variable from text resource
*
* @param resource - Text resource
* @return List - list of document fragment variables
* @pad.exclude Exclude from Published API.
*/
public static List getTextVariables(Resource resource) {
List textVariableList = new ArrayList();
Resource itemsResource = resource.getChild(GuideConstants.ITEMS_NODENAME);
if (itemsResource != null) {
Iterable variableIterator = itemsResource.getChildren();
for (Resource variable : variableIterator) {
TextVariable textVariable = variable.adaptTo(TextVariable.class);
textVariableList.add(textVariable);
}
}
return textVariableList;
}
/**
* Generic utility to parse adobe sign date fields from HTML and convert date fields default value in its date format.
*
* @param htmlVal - stringified html having adobe sign text tags
* @return String html, with correct default values for date
* @pad.exclude Exclude from Published API.
*/
public static String formatDateDefaultValues(String htmlVal) {
String result = htmlVal;
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-mm-dd");
Pattern pattern = Pattern.compile("\\{\\{[*]?[^:]*_es_:[^:]*:isdate(\\(format=[\\\"\\']?([^\\\"\\'\\)]*)[\\\"\\']?\\))?(:default\\([\\\"\\']?([^\\\"\\'\\)]*)[\\\"\\']?\\))?[^\\}]*\\}\\}");
Matcher matcher = pattern.matcher(htmlVal);
while (matcher.find()) {
String dateTextTag = matcher.group(0);
String dateFormat = matcher.group(2);
String defaultDateStr = matcher.group(4);
if (StringUtils.isNotEmpty(defaultDateStr)) {
if (StringUtils.isEmpty(dateFormat)) {
dateFormat = "mm/dd/yy";
}
try {
Date defaultDate = inFormat.parse(defaultDateStr);
SimpleDateFormat outFormat = new SimpleDateFormat(dateFormat);
String formattedDefaultDateStr = outFormat.format(defaultDate);
String correctedDateTextTag = dateTextTag.replace(defaultDateStr, formattedDefaultDateStr);
result = result.replace(dateTextTag, correctedDateTextTag);
} catch (ParseException e) {
// invalid date, do nothing
}
}
}
return result;
}
/**
* Utility to update signer information in Static text/ guide textdraw HTML, while creating guideJson
*
* @pad.exclude Exclude from Published API.
*/
public static String updateSigner(String name, int signerIndex, String htmlVal) {
Pattern pattern = Pattern.compile("(\\{\\{[*]?" + name + "_es_:[*]?signer(\\d+)[:}])");
Matcher matcher = pattern.matcher(htmlVal);
while (matcher.find()) {
String fieldString = matcher.group(1);
String fieldSignerIndex = matcher.group(2);
String newFieldString = fieldString.replace("signer" + fieldSignerIndex, "signer" + signerIndex);
htmlVal = htmlVal.replace(fieldString, newFieldString);
}
return htmlVal;
}
/**
* Generic utility to get service resource resolver
*
* @pad.exclude Exclude from Published API.
*/
public static ResourceResolver getServiceResourceResolver(ResourceResolverFactory resourceResolverFactory) {
try {
return resourceResolverFactory.getServiceResourceResolver(null);
} catch (Exception e) {
logger.error("Cannot provide serviceResourceResolver", e);
}
return null;
}
public static ResourceResolver getCloudServiceUserResourceResolver(ResourceResolverFactory resourceResolverFactory) {
ResourceResolver resourceResolver = null;
if (resourceResolverFactory != null) {
try {
Map authenticationInfo = new HashMap();
authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, GuideConstants.CLOUD_SERVICE_USER);
resourceResolver = resourceResolverFactory.getServiceResourceResolver(authenticationInfo);
} catch (LoginException e) {
logger.error("Cannot provide service resource resolver", e);
}
}
return resourceResolver;
}
/**
* Generic utility to convert string into Map
*
* @pad.exclude Exclude from Published API.
*/
public static Map convertStringToMap(String params) {
Map paramMap = new HashMap();
if (params != null) {
String[] strategyParams = params.split(",");
for (String param : strategyParams) {
String[] keyValue = param.split("=");
if (keyValue.length == 2) {
paramMap.put(keyValue[0], keyValue[1]);
} else {
// invalid case, adding both param then
paramMap.put(param, param);
}
}
}
return paramMap;
}
/**
* @pad.exclude Exclude from Published API.
*/
public static boolean hasNestablePanelLayout(GuideNode parentNode, GuideNode node) {
try {
if (parentNode == null || !GuideUtils.isLayoutablePanel(parentNode)) {
return false;
} else if (node == null || !GuideUtils.isLayoutablePanel(node)) {
return false;
} else {
String parentNodeLayout = parentNode.getLayoutPath();
if (parentNodeLayout != null && (parentNodeLayout.startsWith("/libs/") || parentNodeLayout.startsWith("/apps/"))) {
parentNodeLayout = parentNodeLayout.substring(6);
}
String nodeLayout = node.getLayoutPath();
if (nodeLayout != null && (nodeLayout.startsWith("/libs/") || nodeLayout.startsWith("/apps/"))) {
nodeLayout = nodeLayout.substring(6);
}
return StringUtils.equals(parentNodeLayout, nodeLayout);
}
} catch (Exception e) {
throw new GuideException(e);
}
}
/**
* This is a public api used to extract the guideContainer asset from the content.
* Returns inline guide container if there is no guideRef property present in the guideContainer
* else returns the guideContainer present inline
* @param request sling http servlet request
* @param resource sling resource
* @return path to the form container
*/
public static String getGuideContainerPath(SlingHttpServletRequest request, Resource resource) {
String guideContainerPath = null;
//For authoring if guideContainerNodeName is passed as a parameter it gets highest priority,
//otherwise check if nodeName available in ThreadLocal, else keep the default container name
String guideContainerNodeName = GuideConstants.GUIDECONTAINER_NODENAME;
String containerParamValue = request.getParameter(GuideConstants.GUIDE_CONTAINER_NODE_PARAMETER);
if (containerParamValue != null) {
guideContainerNodeName = containerParamValue;
} else if (GuideContainerThreadLocal.getGuideContainerName() != null) {
guideContainerNodeName = GuideContainerThreadLocal.getGuideContainerName();
} else {
logger.debug("Guide container name not found in ThreadLocal.");
}
try {
ResourceResolver resolver = request.getResourceResolver();
Resource currentResource = resource;
// Search the guide Container by walking up the hierarchy
while (currentResource != null && !currentResource.getResourceType().equals(GuideConstants.RT_PAGE)) {
String normalizedNodeType = GuideUtils.getNormalizedNodeType(currentResource.getResourceType(),
currentResource.getResourceSuperType());
if (GuideConstants.CONTAINER_RESOURCES.contains(normalizedNodeType)) {
guideContainerPath = currentResource.getPath();
break;
}
currentResource = currentResource.getParent();
}
if (guideContainerPath == null) {
if (currentResource != null && currentResource.getResourceType().equals(GuideConstants.RT_PAGE)) {
guideContainerPath = resource.getPath() + "/" + guideContainerNodeName;
}
}
Resource guideContainerResource = request.getResourceResolver().getResource(guideContainerPath);
// If this API is used externally, then guideContainerResource would be null
// As of today, this API is used to check if the request was initiated by a form
if (guideContainerResource == null) {
guideContainerPath = null;
} else {
final ValueMap properties = ResourceUtil.getValueMap(guideContainerResource);
String guideRef = properties.get("guideRef", null);
if (guideRef != null && guideRef.length() != 0) {
// before setting the path, check if the path is correct
String path = GuideUtils.guideRefToGuidePath(guideRef);
Resource guideContainer = request.getResourceResolver().getResource(path);
if (guideContainer != null) {
guideContainerPath = path;
} else {
logger.error("No guide found in guide reference present in guide container");
}
}
}
} catch (Exception e) {
throw new GuideException("No guide Container found", e);
}
return guideContainerPath;
}
/**
* Get the JSON representation of a Resource
*
* @param resource Resource to turn into JSON
* @return JSON representation of the resource
* @pad.exclude Exclude from published API
*/
public static JSONObject resourceToJSON(final Resource resource) throws Exception {
/* Node properties to exclude from the JSON object. */
final Set propertiesToIgnore = new HashSet() {{
add("jcr:created");
add("jcr:createdBy");
add("jcr:versionHistory");
add("jcr:predecessors");
add("jcr:baseVersion");
add("jcr:uuid");
add("jcr:data");
add("jcr:lastModified");
add("cq:lastModified");
add("cq:lastRolledout");
add("cq:lastRolledoutBy");
add("cq:lastModifiedBy");
add("jcr:lastModifiedBy");
}};
final StringWriter stringWriter = new StringWriter();
final JsonResourceWriter jsonWriter = new JsonResourceWriter(propertiesToIgnore);
JSONObject jsonObject = null;
try {
/* Get JSON with no limit to recursion depth. */
jsonWriter.dump(resource, stringWriter, -1);
jsonObject = new JSONObject(stringWriter.toString());
} catch (JSONException e) {
throw new Exception("Could not create JSON from resource at path " + resource.getPath(), e);
}
return jsonObject;
}
/**
* Gets the template JSON of the field from resource type.
*
* @param resourceType
* @param resolver
* @return
* @throws Exception
* @pad.exclude exclude from published api
*/
public static JSONObject getTemplateJsonForField(String resourceType, ResourceResolver resolver) throws Exception {
JSONObject result = null;
if (resolver != null && StringUtils.isNotBlank(resourceType)) {
ComponentManager componentManager = resolver.adaptTo(ComponentManager.class);
// get the resource at the given type
Component component = componentManager.getComponent(resourceType);
// walk through the super component hierarchy
while (component != null) {
// get the template json of the resource
Resource templateNode = resolver.getResource(component.getTemplatePath());
if (templateNode != null) {
// get the json of the template node
result = GuideUtils.resourceToJSON(templateNode);
break;
}
component = component.getSuperComponent();
}
}
return result;
}
/**
* Adds the template json of the field from resource type.
*
* @param currentJsonObject
* @param resourceType
* @param resolver
* @param guideNodeClass
* @return
* @throws Exception
* @pad.exclude exclude from published api
*/
public static JSONObject addTemplateJsonToField(JSONObject currentJsonObject, String resourceType, ResourceResolver resolver, String guideNodeClass) throws Exception{
if(StringUtils.isBlank(resourceType) && StringUtils.isNotBlank(guideNodeClass)) {
resourceType = nodeClassToResourceTypeMap.get(guideNodeClass);
currentJsonObject.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, resourceType);
}
JSONObject templateObj = getTemplateJsonForField(resourceType, resolver);
if(templateObj != null){
//Add the template object
Iterator jsonKeys = templateObj.keys();
while(jsonKeys.hasNext()){
String jsonKey = jsonKeys.next();
//Template shouldn't override json.
if(!currentJsonObject.has(jsonKey)) {
currentJsonObject.put(jsonKey, templateObj.get(jsonKey));
}
}
}
return currentJsonObject;
}
/**
*
* @param request
* @param guideContainerPath
* @return
* @pad.exclude Exclude from published API
*/
public static List getFileAttachmentList(SlingHttpServletRequest request, String guideContainerPath) {
ResourceResolver resourceResolver = request.getResourceResolver();
String rootPanelPath = guideContainerPath + "/" + NodeStructureUtils.ROOTPANEL_NODENAME + "/" + GuideConstants.ITEMS_NODENAME;
Resource guideRootPanel = resourceResolver.getResource(rootPanelPath);
ArrayList result = new ArrayList();
GuideUtils.walkThroughContent(result, guideRootPanel, GuideConstants.RT_GUIDEFILEUPLOAD);
return result;
}
/**
*
* @param contextPropertyName
* @param request
* @return
* @pad.exclude Exclude from published API
*/
public static Object consumeContextProperty(String contextPropertyName, SlingHttpServletRequest request) {
Object contextProp = request.getAttribute(contextPropertyName);
request.removeAttribute(contextPropertyName);
return contextProp;
}
/**
* This API is for checking whether the text box field allows filling rich text or not
*
* @param jsonObject
* @return boolean value indicating whether the field allow rich text or not
* @pad.exclude Exclude from Published API.
*/
public static boolean isRichTextField(JSONObject jsonObject) throws JSONException {
if (jsonObject.has(GuideConstants.RICHTEXT_ALLOWED)) {
return jsonObject.getBoolean(GuideConstants.RICHTEXT_ALLOWED);
}
return false;
}
public static boolean setToolbarLabel(String name, String title, EditContext editContext, SlingHttpServletRequest request) {
if (editContext != null) {
EditConfig editConfig = editContext.getEditConfig();
if (editConfig != null) {
Toolbar tb = editConfig.getToolbar();
if (tb != null) {
if (name != null) {
tb.add(0, new Toolbar.Label(title + name));
}
tb.add(1, new Toolbar.Separator());
return true;
}
}
}
return false;
}
/**
* Encodes the given string as HTML content
* @param str string to encode as HTML content
* @param xssapi {@link XSSAPI} instance
* @return encoded HTML content
*/
public static String encodeForHtml(String str, XSSAPI xssapi) {
String result = xssapi.encodeForHTML(str);
return result == null ? "" : result;
}
/**
* Encodes the given string as HTML attribute
* @param str string to encode as HTML attribute
* @param xssapi {@link XSSAPI} instance
* @return encoded HTML attribute
*/
public static String encodeForHtmlAttr(String str, XSSAPI xssapi) {
String result = xssapi.encodeForHTMLAttr(str);
return result == null ? "" : result;
}
/**
* Encodes the given string as java script content
* @param str string to encode as java script content
* @param xssapi {@link XSSAPI} instance
* @return encoded JS string
*/
public static String encodeForJSString(String str, XSSAPI xssapi) {
String result = xssapi.encodeForJSString(str);
return result == null ? "" : result;
}
public static String filterHtml(String str, XSSAPI xssapi) {
String result = xssapi.filterHTML(str);
return result == null ? "" : result;
}
public static String getDefaultLocale(Resource resource) {
String defaultLocale = GuideConstants.DEFAULT_FALLBACK_LOCALE;
try {
Node containerNode = resource.adaptTo(Node.class);
if (containerNode != null) {
Node parentNode = containerNode.getParent();
if (parentNode != null) {
if (parentNode.hasProperty(JcrConstants.JCR_LANGUAGE)) {
defaultLocale = parentNode.getProperty(JcrConstants.JCR_LANGUAGE).getString();
}
}
}
} catch (Exception e) {
logger.error("Unable to access Page Locale", e);
}
return defaultLocale;
}
public static String getThemeClientLibName(Resource resource) {
try {
Node containerNode = resource.adaptTo(Node.class);
if (containerNode != null && containerNode.hasProperty(GuideConstants.THEME_CLIENTLIB)) {
String theme = containerNode.getProperty(GuideConstants.THEME_CLIENTLIB).getString();
if (StringUtils.isNotBlank(theme)) {
Resource themeResource = resource.getResourceResolver().getResource(theme + "/jcr:content/metadata");
if (themeResource != null) {
Node themeNode = themeResource.adaptTo(Node.class);
if (themeNode != null && themeNode.hasProperty("clientlibCategory")) {
return themeNode.getProperty("clientlibCategory").getString();
}
} else {
logger.warn("Unable to retrieve the theme resource: " + theme);
}
}
}
} catch (RepositoryException e) {
logger.error("Unable to get Client lib name: " + e.getMessage(), e);
}
return "";
}
/**
* @param request
* @param guideContainerResource
* @return the first locale in the accept Lang header, which has a correspoiding guide-i18n clientlib
*/
public static String getLocale(SlingHttpServletRequest request, Resource guideContainerResource) {
try {
String defaultLocale = getDefaultLocale(guideContainerResource);
String localeCode = null,
clientLibPrefix = "guides.I18N";
Locale locale = null;
// If fate yours ever
// Encounters the spell scribed below
// Thou need to turn your wand to ElGuideUtils.getI18n
// To take equal effect
// As the ingredients used, charm it casts are same
SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
HtmlLibraryManager clientlibManager = bindings.getSling().getService(HtmlLibraryManager.class);
boolean clientLibForDefaultLocaleExists = clientlibManager.getLibraries(new String[]{clientLibPrefix + "." + defaultLocale}, null, true, false).toArray().length > 0;
String acceptLang = request.getParameter(GuideConstants.AF_LANGUAGE_PARAMETER);
if (acceptLang == null || acceptLang.trim().isEmpty()) {
acceptLang = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
}
if (acceptLang == null || acceptLang.trim().isEmpty()) {
acceptLang = defaultLocale;
}
String[] locales = StringUtils.split(acceptLang, ",");
for (int i = 0; i < locales.length; i++) {
//strip the priority, if present
localeCode = StringUtils.substringBefore(locales[i], ";");
// locales have format language-country and since we do not store the - in the clientlib name,
// remove that
String[] splitLocale = StringUtils.split(localeCode, "-");
localeCode = splitLocale[0].toLowerCase();
if (splitLocale.length > 1) {
localeCode += splitLocale[1].toUpperCase(); // if locale has country include that
}
String[] categories = new String[]{clientLibPrefix + "." + localeCode};
Collection libraries = clientlibManager.getLibraries(categories, null, true, false);
boolean clientLibForLocaleExists = libraries.toArray().length > 0;
if (clientLibForLocaleExists) {
return localeCode;
} else if (splitLocale.length > 1) {
// Fall back
// if the localeCOUNTRY called lib is not present
// try with locale only
categories = new String[]{clientLibPrefix + "." + splitLocale[0].toLowerCase()};
libraries = clientlibManager.getLibraries(categories, null, true, false);
clientLibForLocaleExists = libraries.toArray().length > 0;
if (clientLibForLocaleExists) {
return splitLocale[0].toLowerCase();
}
}
}
if (clientLibForDefaultLocaleExists)
return defaultLocale;
return GuideConstants.DEFAULT_FALLBACK_LOCALE;
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new GuideException(e);
}
}
/**
* @param request
* @param guideFieldResource
* @return the i18n object for the guide level dictionary
*/
public static I18n getI18n(SlingHttpServletRequest request, Resource guideFieldResource) {
I18n i18n = null;
ResourceResolver resourceResolver = request.getResourceResolver();
try {
String acceptLang = GuideUtils.getAcceptLang(request);
// If given resource is inside a template, then create the i18n object from dictionary corresponding
// to the form in which that template is used.
if (isEditableTemplateResource(guideFieldResource)) {
String formAssetPath = resourceResolver.resolve(request,request.getRequestURI()).getPath(); // TODO: Use some other method to get the guideContainer referring this template resource.
formAssetPath = formAssetPath.substring(request.getContextPath().length()); // Using hackish method, by resolving the requestURI to resource path and manually
String formPath = formAssetPath.replace(GuideConstants.FM_DAM_ROOT, GuideConstants.FM_AF_ROOT); // handling the context path. Some use cases might break.
guideFieldResource = resourceResolver.getResource(formPath);
}
String containerPath = getGuideContainerPath(request, guideFieldResource);
// if containerPath is null, traverse from cq:page node to search for container path
if (containerPath == null || containerPath.isEmpty()) {
containerPath = GuideUtils.getGuideContainerPathFromResource(request, guideFieldResource);
}
String baseName = "";
if (StringUtils.isNotBlank(containerPath)) {
baseName = containerPath + "/assets/dictionary";
Locale locale = new Locale(acceptLang);
i18n = new I18n(request.getResourceBundle(baseName, locale));
} else if (request != null) {
i18n = new I18n(request.getResourceBundle(request.getLocale()));
} else {
i18n = new I18n(request.getResourceBundle(null));
}
} catch (Exception e) {
// Do nothing
logger.error("There was certainly some problem in geti18n api", e);
// Not wanting to throw any exceptions here so just logging it
}
return i18n;
}
/**
* Checks if given resource lies within any editable template or not
* This API is using the logic of TemplateUtils.isAuthoredTemplate() in CQ/wcm
* to check for editable template node.
* @param resource
* @return
* @pad.exclude
*/
public static Boolean isEditableTemplateResource (Resource resource) {
Boolean result = false;
Resource pageResource = getPageResource(resource);
if (pageResource != null ) {
Resource pageParent = pageResource.getParent();
// If the page's parent is a cq:Template node and it has all the 3 nodes (structure, policies and initial), then it is an editable template.
if (GuideConstants.CQ_TEMPLATE.equals(pageParent.getResourceType())) {
result = pageParent.getChild(GuideConstants.TEMPLATE_INITIAL_NODE) != null &&
pageParent.getChild(GuideConstants.TEMPLATE_POLICIES_NODE) != null &&
pageParent.getChild(GuideConstants.TEMPLATE_STRUCTURE_NODE) != null;
}
}
return result;
}
/**
* Returns the cq:Page resource by walking up in the resource hierarchy
* @pad.exclude Exclude from Published API.
*/
public static Resource getPageResource (Resource resource) {
while(resource != null && !GuideConstants.RT_PAGE.equals(resource.getResourceType())) {
resource = resource.getParent();
}
return resource;
}
/**
* @param resourceBundleProvider
* @param containerResource
* @param locale
* @return the i18n object for the guide level dictionary
*/
public static I18n getI18n(ResourceBundleProvider resourceBundleProvider, Resource containerResource, Locale locale) {
if (resourceBundleProvider != null && containerResource != null && locale != null) {
return new I18n(resourceBundleProvider.getResourceBundle(containerResource.getPath(), locale));
}
return null;
}
/**
* Gives the mime type of data which as per the data model
* configured with the form
*
* @param formResource resource of adaptive form container
* @return string representing the mime type
*/
public static String getDataMimeType(Resource formResource) {
String mimeType = GuideConstants.CONTENT_TYPE_APPLICATION_XML;
if (formResource != null) {
GuideContainer guideContainerBean = GuideContainer.from(formResource);
GuideSchemaType schemaType = guideContainerBean.getSchema();
if (schemaType != null) {
// For formdatamodel and jsonschema, the prefillDataType is json but for other form models, it is xml.
if (GuideSchemaType.JSON.equals(schemaType) || GuideSchemaType.FDM.equals(schemaType)) {
mimeType = GuideConstants.CONTENT_TYPE_APPLICATION_JSON;
}
}
}
return mimeType;
}
/**
* Gives the schema type of data which is configured with the form
*
* @param formContainerJson json of adaptive form container
* @return String representing schemaType of form it could have any of the following value
* - none, formtemplates, xmlschema, jsonschema, formdatamodel
* @deprecated Use {@link com.adobe.aemds.guide.common.GuideContainer#getSchemaType()} instead
*/
public static String getSchemaType(JSONObject formContainerJson) {
String type = GuideSchemaType.BASIC.getValue();
String schemaType = formContainerJson.optString(GuideConstants.SCHEMA_TYPE, "");
if (StringUtils.isNotEmpty(schemaType) && GuideSchemaType.isGuideSchemaType(schemaType)) {
type = schemaType;
} else if (StringUtils.isNotEmpty(formContainerJson.optString(GuideConstants.XSD_REF))) {
type = GuideSchemaType.XSD.getValue();
} else if (StringUtils.isNotEmpty(formContainerJson.optString(GuideConstants.XDP_REF))) {
type = GuideSchemaType.XDP.getValue();
}
return type;
}
/**
* Gives the afDataSom for an adaptive form field
*
* @param schemaType of adaptive form
* @param name of adaptive form field
* @param bindRef of adaptive form field
* @return afDataSom of adaptive form field
*/
public static String getAfDataSom(String schemaType, String name, String bindRef) {
String identifier = name;
String fieldType = GuideConstants.BASIC;
// set type if the associated field has bindref, else type will be none (unbound field)
if (StringUtils.isNotEmpty(bindRef)) {
fieldType = schemaType;
identifier = bindRef;
}
return fieldType + ":" + identifier;
}
/**
* Gives JSONObject of Adaptive Form field/panel corresponding to given SOM Expression
*
* @param formContainerJson adaptive form container JSON
* @param somExpression som expression of adaptive form panel/field
* @return JSONObject of Adaptive Form field/panel corresponding to given SOM Expression
*/
public static JSONObject somToAdapativeFormItem(JSONObject formContainerJson, String somExpression) {
JSONObject afItemJson = null;
if (StringUtils.isEmpty(somExpression) || formContainerJson == null) {
return afItemJson;
}
if ("guide[0].guide1[0]".equals(somExpression)) {
return formContainerJson;
}
try {
JSONObject rootPanelJSon = formContainerJson.getJSONObject(GuideConstants.ROOTPANEL_NODENAME);
if ("guide[0].guide1[0].guideRootPanel[0]".equals(somExpression)) {
return rootPanelJSon;
}
String afItemSom = somExpression.replaceFirst("guide\\[0\\]\\.guide1\\[0\\]\\.guideRootPanel\\[0\\]\\.", "");
afItemJson = searchAFItemForSom(rootPanelJSon, afItemSom);
} catch (JSONException jsonException) {
logger.error("Error creating signer info " + jsonException.getMessage(), jsonException);
}
return afItemJson;
}
/**
* Recursively traverse json for finding the field/panel, for given SOM
* @param afItemJson
* @param parentSom
* @return
*/
private static JSONObject searchAFItemForSom(JSONObject afItemJson, String parentSom) {
JSONObject parentJson = afItemJson;
String afItemSom = parentSom;
if (parentJson != null) {
String fieldName = afItemSom.substring(0, afItemSom.indexOf("["));
parentJson = parentJson.optJSONObject(GuideConstants.ITEMS_NODENAME);
// if its not a panel then its a field, and field does have child, hence invalid SOM
if (parentJson == null && StringUtils.isEmpty(fieldName)) {
return null;
}
Iterator keys = parentJson.keys();
// check with the name of all its children
while (keys.hasNext()) {
String key = keys.next();
JSONObject childJson = parentJson.optJSONObject(key);
if (childJson != null && fieldName.equals(childJson.optString(GuideConstants.NAME))) {
parentJson = childJson;
break;
}
}
int nextIndex = afItemSom.indexOf(".");
// check if we fully traversed som Expression, or there is more to traverse
if (nextIndex != -1) {
// shorten the som for the traversed part
afItemSom = afItemSom.substring(nextIndex + 1);
// traverse for remainder som
return searchAFItemForSom(parentJson, afItemSom);
} else {
return parentJson;
}
}
return null;
}
/**
* Utility to convert a RequestParameter to String
*
* @param param RequestParameter
* @pad.exclude Exclude from Published API
*/
public static String paramToString(RequestParameter param) {
if (param != null) {
return param.toString();
}
return null;
}
/**
* Utility to convert an AF(Adaptive Form) meta data path to the actual adaptive forms path
*
* @param guideRefPath path of the adaptive forms metadata node
* @return the path of the adaptive form
*/
//TODO This api assumes the guideContainer name to be guideContainer but in case of ABTesting it can be guideContainer2.
public static String guideRefToGuidePath(String guideRefPath) {
// @todo: have to introduce notion of channels here in future
if (StringUtils.startsWith(guideRefPath, GuideConstants.FM_DAM_ROOT)) {
return GuideConstants.FM_AF_ROOT + StringUtils.substringAfter(guideRefPath, GuideConstants.FM_DAM_ROOT) + GuideConstants.FM_AF_GUIDECONTAINER;
} else {
return guideRefPath;
}
}
/**
* Utility to convert an MC DOCUMENT meta data path to the actual mc document path
*
* @param guideRefPath path of the mc document metadata node
* @return the path of the mc document path
*/
public static String guideRefToDocPath(String guideRefPath) {
if (StringUtils.startsWith(guideRefPath, GuideConstants.FM_DAM_ROOT)) {
return GuideUtils.convertADAssetPathToWebChannelPagePath(guideRefPath) + GuideConstants.FM_AF_GUIDECONTAINER;
} else {
return guideRefPath;
}
}
/**
* This API is for internal purpose.
* This will manipulate the bindRef of the element if there is a bindRef prefix present. This means that the binded node is a fragment in adaptive forms
* so we will need to prefix the schema hierarchy of XFA/XSD
* if the bindRef passed was xfa[0].form[0].form1[0].Subform1[0].Subform2[0].n[0].NumericField1[0]
* and fragment Root is n[0]
* then the new bindref may be like prefix + Fragment root + rest of bindRef after fragment root
* xfa[0].form[0].form1[0].AnotherSubFormWhereFragReferenced[0].n[0].NumericField1[0]
*
* @param bindRefPrefixForFragment this the prefix after which the fragment root would be appended
* @param bindRef Reference to the
* @param fragmentRoot Root of fragment
* @return the manipulated bindref incorporating the fragment related changes
* @pad.exclude Exclude from Published API.
*/
public static String manipulateBindRefForFragments(String bindRefPrefixForFragment, String bindRef, String fragmentRoot) {
String manipulatedBindRef = bindRef;
// Case when the its a xfa binding
if (StringUtils.isNotBlank(bindRefPrefixForFragment) && StringUtils.isNotBlank(fragmentRoot)) {
// This is the case when someone drops fragmentModelRoot in adaptive forms fragment
// and in adaptive forms authoring we know that the panel having fragment binding
// would also lead to same bindRef being created
// e.g if fragment subform is xfa[0].form[0].form1[0].n[0]
// and we map a xfa[0].form[0].form1[0].Subform[0].n[0] fragment to adaptive forms fragment
// then the child of this adaptive forms fragment panel would be
// have xfa[0].form[0].form1[0].n[0] (if it were fragment root) and resolveNode with relative
// som as "" would break the code
if (fragmentRoot.equals(bindRef)) {
return null;
}
// this check is added to handle panels that are converted to fragments and have the fragment model root set to default value of
// "/" for xsd based and "xfa[0].form[0]" for xdp based. This will ensure that the bindref for the child elements are not manipulated.
if (fragmentRoot.equals("/") || fragmentRoot.equals(GuideConstants.XFA_BINDREF_PREFIX)) {
return bindRef;
} else if (StringUtils.startsWith(bindRef, GuideConstants.XFA_BINDREF_PREFIX) && !StringUtils.startsWith(bindRef, fragmentRoot + '.')) {
// this check is to support cross fragment bindRef manipulation for xfa based form.
// if bindRef doesn't start with fragmentRoot then bindRef is not manipulated.
// Example bindRef was xfa[0].form[0].shiporder[0].#subform[0].shipto[0].address[0]
// fragmentRoot was xfa[0].form[0].shiporder[0].#subform[0].item[0]
// as bindRef doesn't start with fragmentRoot, the bindRef is not manipulated.
return bindRef;
} else if (StringUtils.startsWith(bindRef, "/") && !StringUtils.startsWith(bindRef, fragmentRoot + '/')) {
// this check is to support cross fragment bindRef manipulation for xsd based form.
return bindRef;
} else if (StringUtils.startsWith(bindRef, GuideConstants.XFA_BINDREF_PREFIX)) {
// TODO to find out where the actual fragment is located in the XFA
// Example fragment subforms was xfa[0].form[0].form1[0].n[0] with child NumericField1[0]
// Now to use it in the hierarchy xfa[0].form[0].form1[0].Subform1[0].Subform2[0].n[0]
// I would need to replace xfa[0].form[0].form1[0].n[0] with xfa[0].form[0].form1[0].Subform1[0].Subform2[0].n[0]
manipulatedBindRef = bindRefPrefixForFragment + StringUtils.substringAfter(bindRef, fragmentRoot);
} else if (StringUtils.startsWith(bindRef, "/")) {
// its XML Schema binding
manipulatedBindRef = bindRefPrefixForFragment + StringUtils.substringAfter(bindRef, fragmentRoot);
}
}
return manipulatedBindRef;
}
/**
* @param key
* @pad.exclude Exclude from Published API.
*/
public static String getNamespacedKeys(String key) {
return GuideConstants.GUIDE_PREFIX_TO_KEYS + key;
}
/**
* @param original
* @param i18n
* @pad.exclude Exclude from Published API.
*/
public static String translateOrReturnOriginal(String original, I18n i18n) {
String localizedkey, nameSpacedkey;
if (i18n != null) {
nameSpacedkey = getNamespacedKeys(original);
localizedkey = i18n.getVar(nameSpacedkey);
if (!nameSpacedkey.equals(localizedkey)) {
return localizedkey;
}
}
return original;
}
/**
* @param unescaped
* @pad.exclude Exclude from Published API.
*/
public static String escapeXml(String unescaped) {
return StringEscapeUtils.escapeXml(unescaped);
}
/**
* @param guideNodeClass
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideFileUploadModel(String guideNodeClass) {
return GuideConstants.GUIDE_FIELD_FILEUPLOAD.equals(guideNodeClass);
}
/**
* @param guideNodeClass
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideButtonModel(String guideNodeClass) {
return GuideConstants.GUIDE_FIELD_BUTTON.equals(guideNodeClass);
}
/**
* Checks if given node class belongs to guide field
*
* @param guideNodeClass
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideFieldModel(String guideNodeClass) {
return GuideConstants.GUIDE_FIELDS_CLASS_NAMES.indexOf(guideNodeClass) >= 0;
}
/**
* Checks if given node class belongs to guide panel
*
* @param guideNodeClass
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuidePanelModel(String guideNodeClass) {
return GuideConstants.GUIDE_PANELS_CLASS_NAMES.indexOf(guideNodeClass) >= 0;
}
/**
* @param guideNodeClass
* @return
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideCompositeField(String guideNodeClass) {
return GuideConstants.GUIDE_COMPOSITE_FIELD_CLASS_NAMES.indexOf(guideNodeClass) >= 0;
}
/**
* @param guideNodeClass
* @return
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideTnCModel(String guideNodeClass) {
return GuideConstants.GUIDE_FIELD_TERMSANDCONDITIONS.equals(guideNodeClass);
}
/**
* This API is for internal purpose only.
* Returns guideContainer node.
* Input form node or guideContainer node.
*
* @param guideJson
* @return guideContainer JSON object
* @pad.exclude Exclude from Published API.
*/
public static JSONObject getGuideContainer(JSONObject guideJson)
throws GuideException {
try {
return guideJson.has(GuideConstants.ROOTPANEL_NODENAME) ?
guideJson :
guideJson.getJSONObject("jcr:content").getJSONObject("guideContainer");
} catch (Exception e) {
logger.error("Could not get guideContainer within GuideJson : " + guideJson.toString(), e);
throw new GuideException(e);
}
}
/**
* This API is for internal purpose.
* Resource here is an ancestor of guideContainer. It returns the value map of inline guideContainer present in the current page and not the reference guide container.
*
* @param request
* @param elementResource elementResource here should be an ancestor if guideContainer, if it a descendent use the generic api getGuideContainerPath present inside GuideELUtils
* @throws javax.jcr.RepositoryException
* @pad.exclude Exclude from Published API.
*/
public static ValueMap getGuideContainer(final SlingHttpServletRequest request, final Resource elementResource) {
if (elementResource == null)
return null;
// search for all the nodes and get the guideContainer
final Iterator iter = elementResource.listChildren();
Resource guideContainer = null;
while (iter.hasNext() && guideContainer == null) {
final Resource current = iter.next();
if (GuideConstants.CONTAINER_RESOURCES.contains(current.getResourceType())) {
guideContainer = current;
}
}
if (guideContainer != null)
return ResourceUtil.getValueMap(guideContainer);
else {
logger.error("No guideContainer found");
throw new GuideException("No guideContainer found");
}
}
/**
* @param request
* @param resource
* @return
* @throws javax.jcr.RepositoryException
* @pad.exclude Exclude from Published API.
*/
public static Boolean isValidGuide(final SlingHttpServletRequest request, final Resource resource) throws RepositoryException {
ValueMap properties = null;
if (GuideConstants.CONTAINER_RESOURCES.contains(resource.getResourceType())) {
properties = ResourceUtil.getValueMap(resource);
} else {
properties = GuideUtils.getGuideContainer(request, resource);
}
//get the guideRef Attribute
String guideRef = properties.get("guideRef", null);
if (guideRef != null && guideRef.length() != 0) {
// before setting the path, check if the path is correct
String guideContainerPath = guideRefToGuidePath(guideRef); //guideRef.concat(GuideConstants.GUIDECONTAINER_SUFFIX);
Resource guideContainer = request.getResourceResolver().getResource(guideContainerPath);
if (guideContainer == null) {
logger.error("No guide found in guide reference present in guide container");
return false;
}
}
return true;
}
/**
* @param resourceType
* @param resourceSuperType
* @pad.exclude Exclude from Published API.
*/
public static String getNormalizedNodeType(String resourceType, String resourceSuperType) {
String normalizedType = null;
if (resourceType == null && resourceSuperType == null) {
return null;
}
if (StringUtils.startsWith(resourceType, "fd/")) {
normalizedType = resourceType;
} else if (StringUtils.startsWith(resourceType, "/libs/fd/") || StringUtils.startsWith(resourceType, "/apps/fd/")) {
normalizedType = resourceType.substring(6);
} else if (StringUtils.startsWith(resourceSuperType, "fd/")) {
normalizedType = resourceSuperType;
} else if (StringUtils.startsWith(resourceSuperType, "/libs/fd/") || StringUtils.startsWith(resourceSuperType, "/apps/fd/")) {
normalizedType = resourceSuperType.substring(6);
}
return normalizedType;
}
/**
* @param list
* @param elementResource
* @param resourceToBeFound
* @pad.exclude Exclude from Published API.
*/
public static void walkThroughContent(List list, Resource elementResource, final String resourceToBeFound) {
if (elementResource != null) {
Iterator iter = elementResource.listChildren();
while (iter.hasNext()) {
final Resource current = iter.next();
String normalizedNodeType = GuideUtils.getNormalizedNodeType(current.getResourceType(),
current.getResourceSuperType());
if (resourceToBeFound.equals(normalizedNodeType)) {
list.add(current.getPath());
}
walkThroughContent(list, current, resourceToBeFound);
}
}
}
/**
* @param node
* @pad.exclude Exclude from Published API.
*/
public static boolean isLayoutablePanel(GuideNode node) {
return isPanel(node.getResource());
}
/**
* This API converts DAM asset path to adaptive forms page's container path e.g. if the path was /content/dam/formsanddocument/bla/jcr:content
* the return vaule will be /content/forms/af/bla/jcr:content/guideContainer
*
* @param fragRef DAM asset path of Fragment
* @return adaptive forms container path of fragment
* @pad.exclude Exclude from Published API.
*/
public static String convertFMAssetPathToContainerPath(String fragRef) {
// @todo: Have to include channel type here in future, once we support fragments in channels
// Convert asset to adaptive forms page
fragRef = org.apache.commons.lang.StringUtils.replace(fragRef, GuideConstants.FM_DAM_ROOT, GuideConstants.FM_AF_ROOT, 1);
// Now add JCR content and container path
fragRef = fragRef + GuideConstants.JCR_CONTENT + "/" + GuideConstants.GUIDECONTAINER_NODENAME;
return fragRef;
}
private static String removeChannelNameFromEndIfExist(final String pagePath){
String retVal = pagePath;
retVal = StringUtils.substringBefore(retVal, "/" + GuideConstants.NN_CHANNELS + "/");
// remove jcr:content from end if exists
retVal = StringUtils.substringBeforeLast(retVal, GuideConstants.JCR_CONTENT);
return retVal;
}
/**
* Get Form Asset path from the given form container path
* @param guideContainerPath path to the form container
* @return corresponding path of Form Manager Form Asset
*/
public static String convertGuideContainerPathToFMAssetPath(String guideContainerPath) {
String fmPath = StringUtils.substringBefore(guideContainerPath, GuideConstants.FM_AF_GUIDECONTAINER);
String retVal = removeChannelNameFromEndIfExist(fmPath);
retVal = StringUtils.replace(retVal, GuideConstants.FM_AF_ROOT, GuideConstants.FM_DAM_ROOT, 1);
return retVal;
}
/**
* Get Form Asset Meatadata path in form manager for given form container path
* @param guideContainerPath path to the adaptive form container
* @return corresponding path of Form Manager Form Asset Metadata node
*/
public static String convertGuideContainerPathToFMAssetMetadataPath(String guideContainerPath) {
String fmAssetMetadataPath = convertGuideContainerPathToFMAssetPath(guideContainerPath);
fmAssetMetadataPath = fmAssetMetadataPath + GuideConstants.FM_DAM_METADATA;
return fmAssetMetadataPath;
}
/**
* Returns path of XDP used for DoR Template (auto generated or associated)
* dorType = none, dorTemplateRef =
* dorType = generate, dorTemplateRef = /renditions/dorTemplate/runtimeLocale
* dorType = select, dorTemplateRef
*
* @param guideContainerPath
* @param runtimeLocale locale
* @param resourceResolver
* @return path of XDP used for DoR Template
*/
public static String getDoRTemplateRef(String guideContainerPath,
String runtimeLocale, ResourceResolver resourceResolver) {
// if dorType is generate then dorTemplate/ node must exist;
// if not, then create it
String formDAMAssetMetadataPath = GuideUtils.convertGuideContainerPathToFMAssetMetadataPath(guideContainerPath);
Resource containerResource = resourceResolver.getResource(guideContainerPath);
Resource formMetadataResource = resourceResolver.getResource(formDAMAssetMetadataPath);
String dorTemplateRef = "";
if (formMetadataResource != null) {
ValueMap metadata = formMetadataResource.getValueMap();
dorTemplateRef = metadata.get(GuideConstants.XDP_REF, "");
if (StringUtils.isEmpty(dorTemplateRef)) {
dorTemplateRef = (String) metadata.get(GuideConstants.DOR_TEMPLATE_REF);
String dorType = metadata.get(GuideConstants.DOR_TYPE, "");
if ("generate".equals(dorType)) {
dorTemplateRef = GuideUtils.convertGuideContainerPathToFMAssetPath(guideContainerPath) + "/jcr:content/renditions/dorTemplate/" + runtimeLocale;
} else if ("none".equals(dorType)) {
dorTemplateRef = "";
}
}
} else {
// only if this is not an editable template resource, log an error
// since editable template guide container resource, don't have dam asset meta data node
if (containerResource != null && !isEditableTemplateResource(containerResource)) {
logger.error("DAM asset metadata node not available for guide container path: " + guideContainerPath);
}
}
return dorTemplateRef;
}
/**
* @param resourceResolverHelper
* @pad.exclude Exclude from Published API.
*/
public static ResourceResolver getResolverFromResourceResolverHelper(ResourceResolverHelper resourceResolverHelper) {
if (resourceResolverHelper != null) {
return resourceResolverHelper.getResourceResolver();
}
return null;
}
/**
* Returns resource resolver from GuideContainer
*
* @param guideContainer
* @pad.exclude Exclude from Published API.
*/
public static ResourceResolver getResolverFromResource(GuideContainer guideContainer) {
Resource resource = null;
if (guideContainer != null && (resource = guideContainer.getResource()) != null) {
return resource.getResourceResolver();
}
return null;
}
/**
* @param valueMap
* @pad.exclude Exclude from Published API.
*/
public static StrSubstitutor getStringSubstitutor(JSONObject valueMap) {
return new StrSubstitutor(new DataLookUp(valueMap));
}
/**
* Returns wether given resource is of type panel or not.
* @param resource
* @return Boolean true if given resource is of type panel
* @pad.exclude Exclude from Published API.
*/
public static Boolean isPanel(Resource resource) {
Boolean isPanel = Boolean.FALSE;
if(resource != null){
isPanel = resource.isResourceType(GuideConstants.RT_PANEL) ||
resource.isResourceType(GuideConstants.RT_ROOT_PANEL);
}
return isPanel;
}
/**
* Checks if session has property modification permission on resource.
* @param resource
* @return
* @pad.exclude Exclude from Published API.
*/
public static Boolean hasModifyPermission(Resource resource) {
Session currentSession = resource.getResourceResolver().adaptTo(Session.class);
try {
if (currentSession.hasPermission(resource.getPath(), "set_property")) {
return Boolean.TRUE;
}
} catch (RepositoryException e) {
logger.error("unable to check the permissions for setting property on " + resource.getPath(), e);
}
return Boolean.FALSE;
}
/* * Converts Form Fragment having old responsive layout to new responsive layout.
* a) Delete previous /items if present.
* b) Copy fragment resource to current panel.
* c) delete the fragRef flag from current panel and save changes.
* @param fragmentPanelResource
* @param fragmentPath
* @param processConversion
* @return
*/
public static Boolean embedFragmentResources(Resource fragmentPanelResource, String fragmentPath, Boolean processConversion){
ResourceResolver resourceResolver = fragmentPanelResource.getResourceResolver();
try {
Resource prevItemsResources = resourceResolver.getResource(fragmentPanelResource.getPath()+"/items");
if(prevItemsResources!=null){
resourceResolver.delete(prevItemsResources);
}
resourceResolver.copy(fragmentPath, fragmentPanelResource.getPath());
if(processConversion){
convertPanelToNewResponsiveLayout(fragmentPanelResource);
}
ModifiableValueMap modifiableMap = fragmentPanelResource.adaptTo(ModifiableValueMap.class);
modifiableMap.remove(GuideConstants.FRAG_REF);
fragmentPanelResource.getResourceResolver().commit();
} catch (Exception e) {
logger.error("error in embedding adaptive form fragment",e);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
/**
* Converts Form / IC web channel / Fragment having old responsive layout to new responsive layout.
* @param guideContainerResource
* @return Boolean.TRUE if conversion succeeds otherwise returns Boolean.FALSE
* @pad.exclude Exclude from Published API.
*/
public static Boolean convertToNewResponsiveLayout(Resource guideContainerResource) {
Resource rootPanelResource = guideContainerResource.getChild(GuideConstants.ROOTPANEL_NODENAME);
// check for permission
if (!hasModifyPermission(rootPanelResource)) {
logger.error("Has insufficient permissions to convert to new responsive layout " + rootPanelResource.getPath());
return Boolean.FALSE;
}
convertPanelToNewResponsiveLayout(rootPanelResource);
// save changes in the end
try {
rootPanelResource.getResourceResolver().commit();
} catch (PersistenceException e) {
logger.error("Unable to save changes of converted layout " + rootPanelResource.getPath(), e);
}
return Boolean.TRUE;
}
/**
* Converts Panel and its decedents having old responsive layout to new responsive layout.
* @param panelResource
* @pad.exclude Exclude from Published API.
*/
public static void convertPanelToNewResponsiveLayout(Resource panelResource) {
Resource layoutResource = panelResource.getChild(GuideConstants.LAYOUT_NODENAME);
String layoutResourceType = layoutResource.getResourceType();
//if of type old responsive layout
if (GuideConstants.LAYOUT_GRIDFLUIDLAYOUT.equals(layoutResourceType)) {
// modify & remove old responsive layout related properties from layout node
ModifiableValueMap modifiableMap = layoutResource.adaptTo(ModifiableValueMap.class);
modifiableMap.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, GuideConstants.LAYOUT_GRIDFLUIDLAYOUT2);
modifiableMap.remove("columns");
}
Resource itemsResource = panelResource.getChild(GuideConstants.ITEMS_NODENAME);
String itemsResourceType = itemsResource.getResourceType();
if (GuideConstants.LAYOUT_GRIDFLUIDLAYOUT.equals(itemsResourceType)) {
// remove layout related properties from items node
ModifiableValueMap modifiableMap = itemsResource.adaptTo(ModifiableValueMap.class);
modifiableMap.remove(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY);
}
for (Resource item : itemsResource.getChildren()) {
ModifiableValueMap modifiableMap = item.adaptTo(ModifiableValueMap.class);
modifiableMap.remove(GuideConstants.LAYOUT_COLSPAN);
if (item.isResourceType(GuideConstants.RT_PANEL)) {
convertPanelToNewResponsiveLayout(item);
}
}
}
/**
*
* @param panelResource
* @return Boolean.TRUE on first occurrence of old responsive layout
* Boolean.FALSE on first occurrence of new responsive layout
* otherwise null
* @pad.exclude Exclude from Published API.
*/
public static Boolean isOldResponsiveLayout(Resource panelResource) {
//only panel resources have layout
if (!isPanel(panelResource)) {
return null;
}
Resource layoutResource = panelResource.getChild(GuideConstants.LAYOUT_NODENAME);
if (layoutResource == null) {
return null;
}
String layoutResourceType = layoutResource.getResourceType();
//return true if old responsive layout
if (GuideConstants.LAYOUT_GRIDFLUIDLAYOUT.equals(layoutResourceType)) {
return Boolean.TRUE;
} else if (GuideConstants.LAYOUT_GRIDFLUIDLAYOUT2.equals(layoutResourceType)) {
return Boolean.FALSE;
}
//we don't consider fragments used by reference here
Resource itemsResource = panelResource.getChild(GuideConstants.ITEMS_NODENAME);
if (itemsResource != null && itemsResource.hasChildren()) {
for (Resource itemResource : itemsResource.getChildren()) {
//return true on first occurrence of old responsive layout, no need to iterate full hierarchy
// or return false on first occurrence of new responsive layout
Boolean isOldResponsiveLayout = isOldResponsiveLayout(itemResource);
if (isOldResponsiveLayout != null) {
return isOldResponsiveLayout;
}
}
}
return null;
}
/**
* Returns weather the panel resource or any of its hierarchy has old responsive layout in it.
* @param panelResource
* @return Boolean true if panel resource or any of its hierarchy has old responsive layout in it
* @pad.exclude Exclude from Published API.
*/
public static Boolean hasOldResponsiveLayout(Resource panelResource) {
Boolean isOldResponsiveLayout = isOldResponsiveLayout(panelResource);
if (isOldResponsiveLayout != null) {
return isOldResponsiveLayout;
}
return Boolean.FALSE;
}
/**
* @param resource
* @param slingRequest
* @pad.exclude Exclude from Published API.
*/
public static GuidePanel getRootPanel(Resource resource, SlingHttpServletRequest slingRequest) {
Iterator iter = resource.listChildren();
GuidePanel rootPanel = null;
ResourceResolver resourceResolver = resource.getResourceResolver();
while (iter.hasNext() && rootPanel == null) {
final Resource current = iter.next();
String name = current.getName();
if (GuideConstants.ROOTPANEL_NODENAME.equals(name)) {
rootPanel = new GuidePanel();
SimpleBindings bindings = new SimpleBindings();
bindings.put("resource", current);
bindings.put("request", slingRequest);
rootPanel.init(bindings);
}
}
return rootPanel;
}
/**
* @param slingRequest
* @pad.exclude Exclude from Published API.
*/
public static GuideModuleImporter getGuideModuleImporter(SlingHttpServletRequest slingRequest) {
SlingBindings bindings = null;
GuideModuleImporter guideModuleImporter = null;
if (slingRequest != null) {
bindings = (SlingBindings) slingRequest.getAttribute(SlingBindings.class.getName());
// binding would be null, if this function is invoked from Servlet or there is no request
if (bindings != null) {
guideModuleImporter = bindings.getSling().getService(GuideModuleImporter.class);
}
}
return guideModuleImporter;
}
/**
* @param resource
* @pad.exclude Exclude from Published API.
*/
public static Resource getRootPanel(Resource resource) {
try {
if (resource != null) {
Iterator itemKeys = resource.getChildren().iterator();
while (itemKeys.hasNext()) {
Resource item = itemKeys.next();
ValueMap valueMap = item.adaptTo(ValueMap.class);
if (valueMap.get(GuideConstants.SLING_RESOURCE_TYPE) != null) {
String valueOfResourceType = (String) valueMap.get(GuideConstants.SLING_RESOURCE_TYPE);
if (GuideConstants.RT_ROOT_PANEL.equals(valueOfResourceType)) {
return item;
}
}
}
}
} catch (Exception e) {
logger.error("error in getting root panel via guide json", e);
}
return null;
}
/**
* @param str
* @param prefix
* @pad.exclude Exclude from Published API.
*/
public static String removePrefix(String str, String prefix) {
if (str == null || prefix == null) {
return str;
}
if (str.startsWith(prefix)) {
return str.substring(prefix.length());
}
return str;
}
/**
* This method calls staleAssetIndicatorService and gets LMT of the form and related assets - Used to validate Caches - both JSON & HTML
*
* @param guideContainer
* @param staleAssetIndicatorService
* @return lastmodified time from StaleAssetIndicatorService or from jcr:content (parent of guideContainer)
* @pad.exclude Exclude from Published API.
*/
public static Calendar getLastModifiedTimeFromStaleAssetIndicatorService(GuideContainer guideContainer, StaleAssetIndicatorService staleAssetIndicatorService) {
Resource assetNode = null;
Calendar lastModifiedTime = null;
try {
ResourceResolver guideResourceResolver = guideContainer.getResource().getResourceResolver();
if (guideResourceResolver != null) {
String assetPath = convertGuideContainerPathToFMAssetPath(guideContainer.getPath());
assetNode = guideResourceResolver.getResource(assetPath);
// FM DAM root check to help dev test cases not hit cache miss exception
// due to null pointer exception as FM expects this assetNode to be FM asset
if (assetNode != null && StringUtils.startsWith(assetPath, GuideConstants.FM_DAM_ROOT)) {
lastModifiedTime = GuideUtils.getCurrentLMT(assetNode, staleAssetIndicatorService);
} else {
// For Inline guides created using adaptive forms page template, that is, these don't have an asset associated
lastModifiedTime = guideContainer.getLastModifiedTime();
}
}
} catch (Exception e) {
logger.error("Error while calling getLastModifiedTimeFromStaleAssetIndicatorService", e);
}
return lastModifiedTime;
}
/**
* Returns if it's a json based schema type.
*
* @param schemaType
* @return if it's a json based schema type.
* @pad.exclude
*/
public static boolean isJsonBasedSchema(String schemaType) {
return GuideSchemaType.JSON.equals(GuideSchemaType.getGuideSchemaType(schemaType)) || GuideSchemaType.FDM.equals(GuideSchemaType.getGuideSchemaType(schemaType));
}
/**
* Checks if the give adaptive forms(using guidecontainer resource) has a valid XDP Reference to it
*
* @param guideContainer resource of the adaptive form container
* @return false if the resource is null or xdpRef property is null/empty string,
* true otherwise
*/
public static boolean isXDPValid(Resource guideContainer) {
if (guideContainer == null) {
return false;
}
GuideContainer guideContainerBean = GuideContainer.from(guideContainer);
if(!GuideSchemaType.XDP.equals(guideContainerBean.getSchema())) {
return false;
}
String xdpRef = guideContainerBean.getSchemaRef();
if (StringUtils.isBlank(xdpRef)) {
return false;
}
return guideContainerBean.getResource().getResourceResolver().getResource(xdpRef) != null;
}
/**
* Checks if path pointed by metaTemplateRef is valid resource.
*
* @param resourceResolver ResourceResolver to resolve path
* @return false if the resource is null or metaTemplateRef property is null/empty string,
* true otherwise
*/
public static boolean isMetaTemplateValid(ResourceResolver resourceResolver, String metaTemplateRef) {
if (resourceResolver == null) {
return false;
}
if (StringUtils.isBlank(metaTemplateRef)) {
return false;
}
return resourceResolver.getResource(metaTemplateRef) != null;
}
/**
* Get meta-template path associated with guide container.
*
* @param guideContainerResource guide container resource object
* @return returns path to meta-template if exists otherwise empty string
*/
public static String getMetaTemplateRef(Resource guideContainerResource) {
if (guideContainerResource != null && !isGuideContainerResource(guideContainerResource)) {
return "";
}
ValueMap guideContainerProperties = guideContainerResource.getValueMap();
String metaTemplateRef = guideContainerProperties.get(GuideConstants.META_TEMPLATE_REF, "");
Resource print = guideContainerResource.getChild(GuideConstants.PRINT_NODE_RELATIVE_PATH);
if (print != null) {
ValueMap map = print.getValueMap();
if (map.containsKey(GuideConstants.META_TEMPLATE_REF)) {
metaTemplateRef = map.get(GuideConstants.META_TEMPLATE_REF, "");
}
}
return metaTemplateRef;
}
/**
* This is a public api used to identify if a resource is a Guide Container or Wrapper resource
* Returns true if resource is a GuideContainer or Wrapper
* else returns false
*
* @param resource
* @pad.exclude Exclude from Published API.
*/
public static boolean isGuideContainerResource(Resource resource) {
return GuideConstants.CONTAINER_RESOURCES.contains(resource.getResourceType());
}
/**
* This API checks weather the resource's HTML should ever be cached
*
* @param resource container resource
* @return boolean stating if resource can be cached
* @pad.exclude Exclude from Published API.
*/
public static boolean isCacheableContainerResource(Resource resource) {
return GuideConstants.CACHEABLE_CONTAINER_RESOURCES.contains(resource.getResourceType());
}
/**
* API to identify if targeting is enabled for the Adaptive form requested by
* the specified guide container
*
* @param guideContainerResource resource to the adaptive form container
* @return true if targeting enabled false otherwise
*/
public static boolean isTargetEnabled(Resource guideContainerResource) {
ValueMap props = guideContainerResource.getParent().adaptTo(ValueMap.class);
return props.get(GuideConstants.TARGET_ENABLED, false);
}
/**
* API to identify if adobe target is configured for the Adaptive form.
*
* @param resource resource to the adaptive form container
* @return true if adobe target is configured otherwise false
*/
public static boolean isAdobeTargetConfigured(Resource resource) {
InheritanceValueMap valueMap = new HierarchyNodeInheritanceValueMap(resource);
Object cloudserviceConfigs = valueMap.getInherited(Constants.PN_CQ_CLOUD_SERVICE_CONFIGS, String[].class);
if(cloudserviceConfigs != null) {
for (String cloudserviceConfig : (String [])cloudserviceConfigs) {
if (cloudserviceConfig.startsWith("/etc/cloudservices/testandtarget")) {
return true;
}
}
}
return false;
}
/**
* The api returns the alternate (Target B scenario for ABTesting)
* Returns path to the alternate Guide Container
*
* @param requestPathInfo RequestPathInfo object from the request
* @return alternateContainerPath
* @pad.exclude Exclude from Published API.
*/
public static String getAlternateContainerPathFromCurrentContainer(RequestPathInfo requestPathInfo) {
String currentContainerPath = requestPathInfo.getResourcePath();
String extension = null;
if (currentContainerPath == null) {
return null;
}
extension = requestPathInfo.getExtension();
if (extension == null) {
return currentContainerPath.substring(0, currentContainerPath.lastIndexOf("/")) + "/" + GuideConstants.GUIDE_TARGET_ALTERNATE_CONTAINER_NAME;
} else {
return currentContainerPath.substring(0, currentContainerPath.lastIndexOf("/")) + "/" + GuideConstants.GUIDE_TARGET_ALTERNATE_CONTAINER_NAME + "." + extension;
}
}
/**
* validates Adaptive Form (having Signature Step) authored state
*
* @param guideContainer,
* @return list of errors if any
* @pad.exclude Exclude from Published API.
*/
public static List validateFormAuthoredState(GuideContainer guideContainer, String afInitializationState, I18n localI18n) {
List errorList = new ArrayList();
if (!guideContainer.isSignatureConfiguredCorrectly()) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0007));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0007));
}
String xdpRef = guideContainer.getXdpRef();
String dorTemplateRef = guideContainer.getDorTemplateRef();
//check for Signature Step component - "guideNodeClass\":\"esign\"
int esignNodeClassIndex = afInitializationState.indexOf("\"guideNodeClass\\\":\\\"esign\\\"");
if (esignNodeClassIndex > 0) {
//Extracting json string of SignatureStep
int beginIndex = afInitializationState.substring(0, esignNodeClassIndex).lastIndexOf("{");
String signatureStepJsonStr = afInitializationState.substring(beginIndex, afInitializationState.indexOf("}", beginIndex) + 1);
Boolean isEchoSignService = signatureStepJsonStr.contains("\"signingService\\\":\\\"echosign\\\"");
//checking for target version of Signature Step
if (signatureStepJsonStr.contains("\"fd:targetVersion\\\":\\\"1.1\\\"") && isEchoSignService) {
//Adobe Sign should be enabled on guideContainer
if (!guideContainer.isAdobeSignEnabled()) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0001));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0001));
} else if (!guideContainer.isFormFillerFirstSigner()) {
//Form filler should be the first signer for form having signature step
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0002));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0002));
}
} else if (guideContainer.isAdobeSignEnabled() && isEchoSignService) {
//For legacy component Adobe Sign should not be enabled on guideContainer
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0003));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0003));
}
}
Boolean isXDPBased = StringUtils.isNotEmpty(xdpRef);
Boolean isDorConfigured = StringUtils.isNotEmpty(dorTemplateRef);
Boolean canAfProduceDor = isXDPBased || isDorConfigured;
Boolean isDorAutogenerate = "generate".equals(guideContainer.getDoRType());
// Electronic signature to be configured, AF either has to be XDP based or should have associated DOR
if (guideContainer.isAdobeSignEnabled() && !canAfProduceDor) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0004));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0004));
}
// Esign component can not exist without DOR or XDP based
if (esignNodeClassIndex > 0 && !canAfProduceDor) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0005));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0005));
}
//check for Verify Step component - "guideNodeClass\":\"verify\"
Boolean hasVerifyComponent = afInitializationState.contains("\"guideNodeClass\\\":\\\"verify\\\"");
// Verify component can not exist without DOR or XDP based
if (hasVerifyComponent && !canAfProduceDor) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_VERIFY_STEP_0002));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_VERIFY_STEP_0002));
}
//check for adobe sign block component - "guideNodeClass\":\"guideAdobeSignBlock\"
Boolean hasAdobeSignBlockComponent = afInitializationState.contains("\"guideNodeClass\\\":\\\"guideAdobeSignBlock\\\"");
// adobe sign blocks don't have any affect in XDP based AF or Form template associated with DOR
if (hasAdobeSignBlockComponent && !isDorAutogenerate) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_E_SIGN_0006));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_E_SIGN_0006));
}
//Check for minimum count to be 0.
Boolean isMinCountZero = afInitializationState.contains("\\\"minOccur\\\":\\\"0\\\"");
if(isMinCountZero && hasVerifyComponent) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_VERIFY_STEP_0001));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_VERIFY_STEP_0001));
}
Boolean hasDefaultCaptcha = afInitializationState.contains("\"captchaService\\\":\\\"afcaptcha\\\"");
if (hasDefaultCaptcha) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_DEFAULT_CAPTCHA_0001));
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_DEFAULT_CAPTCHA_0001));
}
String aemWorkflowStr = "\"aemWorkflowId\\\":";
int aemWorkflowIndex = afInitializationState.indexOf(aemWorkflowStr);
if (aemWorkflowIndex > -1) {
String errorMsg = localI18n.getVar(AuthoringErrorMessages.AUTHORING_ERROR_MAP.get(AuthoringErrorMessages.MSG_FLAMINGO_0001));
int aemWorkflowEndIndex = afInitializationState.indexOf('}', aemWorkflowIndex) + 1;
String workflowIdsStr = afInitializationState.substring(aemWorkflowIndex+2+aemWorkflowStr.length(), aemWorkflowEndIndex);
try {
Gson gson = new Gson();
Map workflowIdMap = gson.fromJson(StringEscapeUtils.unescapeJava(workflowIdsStr).replace("\\\"", "'"), Map.class);
Iterator> entryIterator = workflowIdMap.entrySet().iterator();
while(entryIterator.hasNext()) {
Map.Entry entry = entryIterator.next();
String workFlowId = entry.getValue();
errorMsg = StringUtils.join(errorMsg, "
"+entry.getKey()+"");
}
} catch (Exception e) {
logger.error("Error while fetching workflow id for smart forms", e);
}
errorList.add(new AuthoringError(errorMsg, AuthoringErrorMessages.MSG_FLAMINGO_0001, AuthoringError.ErrorType.Info));
}
return errorList;
}
/**
* returns whether the dorTemplateRef present in the resource is valid or not
* todo: Have to check if the schema of XSD and dorTemplateRef match?
*
* @param guideContainer,
* @return false if the resource is null, dorTemplateRef property is null or empty string,
* true otherwise
* @pad.exclude Exclude from Published API.
*/
public static boolean isDorTemplateRefValid(Resource guideContainer) {
if (guideContainer == null) {
return false;
}
GuideContainer guideContainerBean = GuideContainer.from(guideContainer);
ValueMap guideContainerProps = guideContainerBean.getResource().adaptTo(ValueMap.class);
String xsdRef = GuideSchemaType.XSD.equals(guideContainerBean.getSchema()) ? guideContainerBean.getSchemaRef() : null,
dorTemplateRef = null;
if (xsdRef == null || xsdRef.length() == 0) {
return false;
} else {
// here it is expected that it is the absolute path of XDP present
// todo: please check for relative path, will depend on how forms manager store XDP in guide container dialog settings
dorTemplateRef = guideContainerProps.get(GuideConstants.DOR_TEMPLATE_REF, null);
}
if (dorTemplateRef != null) {
boolean isValid = true;
try {
isValid = (guideContainer.getResourceResolver().getResource(dorTemplateRef) != null);
} catch (SlingException ex) {
isValid = false;
logger.error("DOR Template present in XDP is either set to null or is relative" + ex.getMessage(), ex);
}
return isValid;
} else {
return false;
}
}
/**
* Returns the xfa compliant locale. If a XFA compliant version is not found then it returns the locale as is
* Eg. For en it returns en_US.
*
* @param locale AEM supported locale
* @return Returns the corresponding XFA compliant locale *
*/
public static String getXFALocale(String locale) {
String xfaLocale = locale;
for (int i = 0; i < GuideConstants.AEM_SUPPORTED_LOCALES.length; i++) {
if (GuideConstants.AEM_SUPPORTED_LOCALES[i].equals(locale)) {
xfaLocale = GuideConstants.AEM_XFA_SUPPORTED_LOCALES[i];
break;
}
}
return xfaLocale;
}
/**
* Returns the runtime locale in format like en-us
*
* @param resource resource to the adaptive form container
* @param slingRequest client request object
* @return Returns the runtime locale if localeLib is present otherwise falls back to
* authoring locale or "en" as last resort
*/
public static String getGuideRuntimeLocale(SlingHttpServletRequest slingRequest, Resource resource) {
int index = 0; // if no resource or guideContainer resource the "en" is fallback
String[] GUIDES_SUPPORTED_CLIENTLIBS = GuideConstants.GUIDES_SUPPORTED_CLIENTLIBS;
String[] supportedLocales = GuideConstants.AEM_SUPPORTED_LOCALES;
//changed operator from or to and so that bindings are initialized only if slingRequest is not null.
if (resource != null && slingRequest != null) {
SlingBindings bindings = (SlingBindings) slingRequest.getAttribute(SlingBindings.class.getName());
if (bindings != null) {
GuideLocalizationService guideLocalizationService = bindings.getSling().getService(GuideLocalizationService.class);
supportedLocales = guideLocalizationService.getSupportedLocales();
GUIDES_SUPPORTED_CLIENTLIBS = GuideUtils.sanitizeLocaleList(supportedLocales);
}
String locale = getLocale(slingRequest, resource);
index = Arrays.asList(GUIDES_SUPPORTED_CLIENTLIBS).indexOf(locale);
// Try to fallback to the author locale
if (index == -1) {
Locale authoringLocale = slingRequest.getLocale();
if (authoringLocale != null) {
index = Arrays.asList(GUIDES_SUPPORTED_CLIENTLIBS).indexOf(authoringLocale.toString());
}
}
// fallback to english
if (index == -1) {
index = 0;
}
}
return supportedLocales[index];
}
/**
* @param containerResource
* @param staleAssetIndicatorService
* @return Calendar LMT of the child asset or LONG_MAX value if service missing
* This method will call form managers' API to check that all
* related child asset's TS and return eldest modified time
* @pad.exclude Exclude from Published API.
*/
public static Calendar getCurrentLMT(Resource containerResource, StaleAssetIndicatorService staleAssetIndicatorService) {
Calendar calendar = Calendar.getInstance();
if (staleAssetIndicatorService != null) {
long currentLMT = staleAssetIndicatorService.getAssetTreeLMT(containerResource);
calendar.setTimeInMillis(currentLMT);
} else {
// Cache miss
logger.info("staleAssetIndicatorService not available : Guide Json cache miss");
calendar.setTimeInMillis(Long.MAX_VALUE);
}
return calendar;
}
/**
* @param request
* @return string consisting of appropriate locale code
* This method will iterate through list of language in "accept-language"
* request header and provide with the appropriate locale code
* after finding the clientlibs available for localization
* Guide Container Locale is the fallback.
* @pad.exclude Exclude from Published API.
*/
public static String getAcceptLang(SlingHttpServletRequest request) {
// request would be null at server side validation
if (request == null) {
return GuideConstants.DEFAULT_FALLBACK_LOCALE;
}
String language = null;
SlingBindings bindings = (SlingBindings) request.getAttribute(SlingBindings.class.getName());
//check the parameter afAcceptLang for accepted language
String afLang = request.getParameter(GuideConstants.AF_LANGUAGE_PARAMETER);
if (afLang != null && !afLang.trim().isEmpty()) {
language = getAcceptLang(afLang, bindings);
}
//if the accepted language is not provided, or invalid, look for the request header
//accept-language
if (language == null) {
String acceptLang = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
if (acceptLang != null && !acceptLang.isEmpty()) {
language = getAcceptLang(acceptLang, bindings);
}
}
if (language != null) {
return language;
}
return getDefaultLocale(request);
}
/**
* @param request
* @return string consisting of default locale
* This method will extract the authoring locale from
* Guide Container Path after resolving resources
* "en" is the last fallback.
* @pad.exclude Exclude from Published API.
*/
private static String getDefaultLocale(SlingHttpServletRequest request) {
try {
Resource resource = request.getResource();
if (resource != null) {
String path = getGuideContainerPath(request, resource);
if (path != null && !path.isEmpty()) {
ResourceResolver guideResourceResolver = request.getResourceResolver();
if (guideResourceResolver != null) {
Resource guideContainerResource = guideResourceResolver.getResource(path);
if (guideContainerResource != null) {
return getDefaultLocale(guideContainerResource);
}
}
}
}
} catch (Exception e) {
logger.error("Guide Resource not found", e);
}
return GuideConstants.DEFAULT_FALLBACK_LOCALE;
}
/**
* @param locale
* @param bindings
* @return string consisting of appropriate locale code for a locale
* @pad.exclude Exclude from Published API.
*/
private static String getAcceptLang(String locale, SlingBindings bindings) {
String acceptLang = locale;
// Q. When can sling bindings be null ?
// Ans. When called from GuideInternalSubmitServlet
if (bindings != null) {
GuideLocalizationService guideLocalizationService = bindings.getSling().getService(GuideLocalizationService.class);
String[] supportedLocales = guideLocalizationService.getSupportedLocales();
String[] supportedLocalesSanitized = GuideUtils.sanitizeLocaleList(supportedLocales);
String localeCode;
// If fate yours ever
// Encounters the spell scribed below
// Thou need to turn your wand to ElGuideUtils.getLocale
// To take equal effect
// As the ingredients used, charm it casts are same
String[] locales = StringUtils.split(acceptLang, ",");
for (int i = 0; i < locales.length; i++) {
//strip the priority, if present
localeCode = StringUtils.substringBefore(locales[i], ";");
// locales have format language-country and since we do not store the - in the clientlib name,
// remove that
String[] splitLocale = StringUtils.split(localeCode, "-");
localeCode = splitLocale[0].toLowerCase();
if (splitLocale.length > 1) {
localeCode += splitLocale[1].toUpperCase(); // if locale has country include that
}
int index = Arrays.asList(supportedLocalesSanitized).indexOf(localeCode);
if (index != -1) {
acceptLang = supportedLocales[index];
return acceptLang;
} else if (splitLocale.length > 1) {
// Fall back
// if the localeCOUNTRY called lib is not present
// try with locale only
index = Arrays.asList(supportedLocalesSanitized).indexOf(splitLocale[0].toLowerCase());
if (index != -1) {
acceptLang = supportedLocales[index];
return acceptLang;
}
}
}
return null;
} else {
return locale;
}
}
/**
* @param guideTypeJsonObject
* @param toCheck
* @param keyToPut
* @param valueToPut
* @param collection
* @pad.exclude Exclude from Published API.
*/
public static void visitToCollectProperties(JSONObject guideTypeJsonObject, String toCheck, String keyToPut, String valueToPut, JSONArray collection) {
try {
if (guideTypeJsonObject.has(toCheck)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put((String) guideTypeJsonObject.get(keyToPut), guideTypeJsonObject.get(valueToPut));
collection.put(jsonObject);
}
if (guideTypeJsonObject.has(GuideConstants.ITEMS_NODENAME)) {
JSONObject items = (JSONObject) guideTypeJsonObject.get(GuideConstants.ITEMS_NODENAME);
Iterator childKeys = items.keys();
while (childKeys.hasNext()) {
visitToCollectProperties((JSONObject) items.get(childKeys.next()), toCheck, keyToPut, valueToPut, collection);
}
}
} catch (Exception e) {
logger.error("Error in visting XML Schema", e);
}
}
/**
* returns the i18 object for the desired locale
*
* @return returns the i18 object for the desired locale
* @pad.exclude Exclude from Published API.
*/
public static I18n getI18nForDesiredLocale(SlingHttpServletRequest request, Resource guideContainerResource, Locale desiredLocale) {
String baseName = null;
if (desiredLocale == null) {
desiredLocale = request.getLocale();
}
if (guideContainerResource != null && request != null) {
baseName = getGuideContainerPath(request, guideContainerResource) + "/assets/dictionary";
if (baseName != null) {
ResourceBundle resourceBundle = request.getResourceBundle(baseName, desiredLocale);
if (resourceBundle != null) {
return new I18n(resourceBundle);
}
}
}
return null;
}
/**
* returns the index of the locale from the GuideConstants.AEM_SUPPORTED_LOCALES
* if locale is not suppoted then index of "en" is returned
*
* @param locale
* @return returns the index of the locale from the GuideConstants.AEM_SUPPORTED_LOCALES
* @pad.exclude Exclude from Published API.
*/
public static int getLocaleIndexFromLocale(String locale, String[] AEM_SUPPORTED_LOCALES) {
String[] GUIDES_SUPPORTED_CLIENTLIBS = GuideUtils.sanitizeLocaleList(AEM_SUPPORTED_LOCALES);
int index = Arrays.asList(GUIDES_SUPPORTED_CLIENTLIBS).indexOf(locale);
if (index == -1) {
index = 0;
}
return index;
}
/**
* This is to sanitize the localisation service locales
* They are in pt-br format, we will try to sanitize them to ptBR format
*
* @param locales
* @return returns a new list of sanitized locales
* @pad.exclude Exclude from Published API.
*/
public static String[] sanitizeLocaleList(String[] locales) {
String localeCode;
String[] sanitizedLocales = new String[locales.length];
for (int i = 0; i < locales.length; i++) {
localeCode = locales[i];
String[] splitLocale = StringUtils.split(localeCode, "-");
localeCode = splitLocale[0].toLowerCase();
if (splitLocale.length > 1) {
localeCode += splitLocale[1].toUpperCase(); // if locale has country include that
}
sanitizedLocales[i] = localeCode;
}
return sanitizedLocales;
}
/**
* Returns the inherited property value of the property from the page containing the resource mentioned.
* @param resource resource
* @param propertyName name of the property
* @return string representing the inherited property value
* @pad.exclude
*/
public static String getInheritedProperty(Resource resource, String propertyName) {
String retVal = null;
if (resource != null) {
final ResourceResolver resourceResolver = resource.getResourceResolver();
if (resourceResolver != null) {
final PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
if (pageManager != null) {
final Page page = pageManager.getContainingPage(resource);
retVal = WCMUtils.getInheritedProperty(page, resourceResolver, propertyName);
}
}
}
return retVal;
}
/**
* To get user session from sling request
*
* @pad.exclude Exclude from Published API.
*/
public static Session getUserSessionFromRequest(SlingHttpServletRequest slingHttpServletRequest) {
return slingHttpServletRequest.getResourceResolver()
.adaptTo(Session.class);
}
/**
* Forwards the given request using HTTP Post to the given post url
*
* @param request sling request
* @param response sling response
* @param postUrl URL to forward the current request
* @return sling http servlet response
*/
public static SlingHttpServletResponse processInternalPostOnRestEndPoint(SlingHttpServletRequest request, SlingHttpServletResponse response, String postUrl) {
SlingHttpServletRequest wrappedRequest = null;
SlingHttpServletResponse wrappedResponse = null;
try {
ParameterMap wrappedParameterMap = GuideUtils.prepareWrappedRequestWithDataXMLAndAttachments(request);
wrappedRequest = new CustomParameterRequest(request, wrappedParameterMap, "POST");
wrappedResponse = new CustomResponse(response);
request.getRequestDispatcher(postUrl).forward(wrappedRequest, wrappedResponse);
} catch (Exception e) {
logger.error("Some Problem While Posting to rest End Point", e);
}
return wrappedResponse;
}
/**
* @param requestParameterMap
* @param key
* @param requestParameter
* @deprecated
* @pad.exclude Exclude from Published API.
*/
public static void addToRequestMap(ParameterMap requestParameterMap, String key, RequestParameter[] requestParameter) {
requestParameterMap.put(key, requestParameter);
}
/**
* @param request
* @pad.exclude Exclude from Published API.
*/
public static ParameterMap prepareWrappedRequestWithDataXMLAndAttachments(SlingHttpServletRequest request) {
ParameterMap wrappedParameterMap = new ParameterMap();
RequestParameterMap originalParams = request.getRequestParameterMap();
List fileAttachments = new ArrayList();
try {
// Add file attachments
for (Map.Entry param : originalParams.entrySet()) {
RequestParameter[] rpm = param.getValue();
if (rpm != null && rpm.length > 0 && !rpm[0].isFormField()) {
FileAttachmentWrapper fileAttachment = new FileAttachmentWrapper(rpm[0].getFileName(), rpm[0].getContentType(), rpm[0].get());
fileAttachments.add(fileAttachment);
}
}
// copy file "attachments" if present
if (fileAttachments.size() > 0) {
RequestParameter[] attachments = new RequestParameter[fileAttachments.size()];
int index = 0;
for (final FileAttachmentWrapper fileAttachment : fileAttachments) {
attachments[index++] = new FileRequestParameter(fileAttachment.getFileName(), IOUtils.toByteArray(fileAttachment.getInputStream()), fileAttachment.getContentType());
}
GuideUtils.addToRequestMap(wrappedParameterMap, GuideConstants.ATTACHMENTS, attachments);
}
// Put dataXml too
GuideUtils.addToRequestMap(wrappedParameterMap, GuideConstants.DATA_XML, originalParams.getValues(GuideConstants.JCR_DATA));
} catch (Exception e) {
logger.error("Not Able to make internal post req parameter", e);
}
return wrappedParameterMap;
}
/**
* Returns the field layout related configuration of the field.
* If one wishes to write own custom layout, the framework is similar to how
* we write custom panel layout
*
* @pad.exclude Exclude from Published API.
*/
public static String getFieldLayout(Resource guideContainerResource, String propertyName, String defaultValue) {
String fieldLayout = defaultValue;
if(guideContainerResource != null) {
// get the properties map for guide container resource
ValueMap properties = guideContainerResource.adaptTo(ValueMap.class);
// Return the field layout present
fieldLayout = properties.get(propertyName, defaultValue);
}
return fieldLayout;
}
/**
* Sets the embed fragment button in the edit bar for the panel based on the title, handler and index.
*
* @param title
* @param editContext
* @param request
* @param fragRef
* @param currentPanelPath
* @param bindRef
* @pad.exclude Exclude from Published API.
*/
public static boolean setEmbedFragButton(String title, EditContext editContext, SlingHttpServletRequest request, String fragRef, String currentPanelPath, String bindRef) {
if (editContext != null) {
EditConfig editConfig = editContext.getEditConfig();
XSSAPI xssapi = request.adaptTo(XSSAPI.class);
if (editConfig != null) {
Toolbar tb = editConfig.getToolbar();
if (tb != null) {
if (title != null) {
tb.add(new Toolbar.Separator());
// fragRef stored was FM asset path , converting it to AF page path
fragRef = StringUtils.replace(fragRef, GuideConstants.FM_DAM_ROOT, GuideConstants.FM_AF_ROOT, 1);
String handler = "function(){guidelib.author.editConfigListeners.embedFragment(\"" + fragRef + "\", \"" + currentPanelPath + "\" ,\"" + bindRef + "\");}";
//NOCHECKMARX - handler must be handled where it's used.
//In this case, panel.jsp has these values from property and resource preventive Reflective XSS All Client.
tb.add(new Toolbar.Button(title, handler));
}
return true;
}
}
}
return false;
}
/**
* Sets the button in the edit bar for the panel based on the title and handler.
*
* @param title
* @param editContext
* @param request
* @param currentPanelPath
* @param bindRef
* @param handler
* @return
* @pad.exclude Exclude from Published API.
*/
public static boolean setButtonForPanel(String title, EditContext editContext, SlingHttpServletRequest request, String currentPanelPath, String bindRef, String handler) {
return setButtonForPanel(title, editContext, request, currentPanelPath, bindRef, handler, null);
}
/**
* Sets the button in the edit bar for the panel based on the title, handler and index.
*
* @param title
* @param editContext
* @param request
* @param currentPanelPath
* @param bindRef
* @param handler
* @param index
* @pad.exclude Exclude from Published API.
*/
public static boolean setButtonForPanel(String title, EditContext editContext, SlingHttpServletRequest request, String currentPanelPath, String bindRef, String handler, Integer index) {
if (editContext != null) {
EditConfig editConfig = editContext.getEditConfig();
if (editConfig != null) {
Toolbar tb = editConfig.getToolbar();
if (tb != null) {
if (index == null) {
index = tb.size();
}
if (title != null) {
tb.add(index, new Toolbar.Separator());
tb.add(index + 1, new Toolbar.Button(title, handler));
}
return true;
}
}
}
return false;
}
/**
* @param responseString
* @param redirectParameters
* @pad.exclude Exclude from Published API.
*/
public static void putQueryParamsToRedirectRequest(String responseString, Map redirectParameters) {
try {
String[] pairs = responseString.split("&");
for (int i = 0; i < pairs.length; i++) {
String[] fields = pairs[i].split("=");
if (fields.length == 2) {
String name = URLDecoder.decode(fields[0].trim(), "UTF-8");
String value = URLDecoder.decode(fields[1].trim(), "UTF-8");
redirectParameters.put(name, value);
}
}
} catch (Exception e) {
logger.error("Error while putting params to redirect Request", e);
}
}
/**
* @param size
* @pad.exclude Exclude from Published API.
*/
public static double parseSize(String size) {
if (size.indexOf("in") >= 0 || size.indexOf("mm") >= 0 || size.indexOf("cm") >= 0 || size.indexOf("pt") >= 0 || size.indexOf("px") >= 0) {
return Double.parseDouble(size.substring(0, size.length() - 2));
}
return 1.00;
}
/**
* @param guideJsonString AF Json
* @pad.exclude Exclude from Published API.
* This is a wrapper API - would cut down all the lazy children from the JSON
*/
public static JSONObject trimLazyChildren(String guideJsonString) {
JSONObject trimmedGuideJson = null;
try {
trimmedGuideJson = new JSONObject(guideJsonString);
trimJsonOfLazyInstances(trimmedGuideJson);
} catch (Exception e) {
logger.error("Could not trim children", e);
}
return trimmedGuideJson;
}
/**
* @param jsonObject
* @pad.exclude Exclude from Published API.
*/
private static void trimJsonOfLazyInstances(JSONObject jsonObject) {
try {
if (jsonObject.has(GuideConstants.OPTIMIZE_RENDER_PERFORMANCE)) {
if (jsonObject.has(GuideConstants.ITEMS_NODENAME)) {
jsonObject.remove(GuideConstants.ITEMS_NODENAME);
}
} else if (jsonObject.has(GuideConstants.ROOTPANEL_NODENAME)) {
trimJsonOfLazyInstances(jsonObject.getJSONObject(GuideConstants.ROOTPANEL_NODENAME));
} else if (jsonObject.has(GuideConstants.ITEMS_NODENAME)) {
JSONObject itemsNode = jsonObject.getJSONObject(GuideConstants.ITEMS_NODENAME);
Iterator> keys = itemsNode.keys();
while (keys.hasNext()) {
String key = (String) keys.next();
JSONObject childItem = itemsNode.getJSONObject(key);
trimJsonOfLazyInstances(childItem);
}
}
} catch (Exception e) {
logger.error("Some exception while removing on demand children", e);
}
}
/**
* Finds a fragment/form with the specified property and having the given path (required for getting in context(manipulated bindrefs/ HTML IDs) fragment/form )
*
* @param jsonObject
* @param propertyName
* @param propertyValue
* @param path
* @param ignorePath if true then the resource should have same jcr:path path is ignored
* @return string having JSON of the fragment/ form
* @pad.exclude Exclude from Published API.
*/
public static String findJsonObjectWithProperty(JSONObject jsonObject, String propertyName, String propertyValue, String path, boolean ignorePath) {
String stringifiedResult = "";
try {
if (jsonObject.has(propertyName) && propertyValue.equals(jsonObject.getString(propertyName)) &&
(ignorePath || path.equals(jsonObject.get(JcrConstants.JCR_PATH)))) {
// clean nested lazy children
JSONObject itemsNode = jsonObject.getJSONObject(GuideConstants.ITEMS_NODENAME);
Iterator> keys = itemsNode.keys();
while (keys.hasNext()) {
String key = (String) keys.next();
JSONObject childItem = itemsNode.getJSONObject(key);
trimJsonOfLazyInstances(childItem);
}
// yay now we are good to go
return jsonObject.toString();
} else if (jsonObject.has(GuideConstants.ROOTPANEL_NODENAME)) {
return findJsonObjectWithProperty(jsonObject.getJSONObject(GuideConstants.ROOTPANEL_NODENAME),
propertyName, propertyValue, path, ignorePath);
} else if (jsonObject.has(GuideConstants.ITEMS_NODENAME)) {
JSONObject itemsNode = jsonObject.getJSONObject(GuideConstants.ITEMS_NODENAME);
Iterator> keys = itemsNode.keys();
while (keys.hasNext()) {
String key = (String) keys.next();
JSONObject childItem = itemsNode.getJSONObject(key);
stringifiedResult += findJsonObjectWithProperty(childItem, propertyName, propertyValue, path, ignorePath);
}
} else {
// its a leaf
return "";
}
} catch (Exception e) {
logger.error("Error while fetching json for " + propertyValue, e);
}
return stringifiedResult;
}
/**
* Finds a fragment/form with the specified property and having the given path (required for getting in context(manipulated bindrefs/ HTML IDs) fragment/form )
*
* @param jsonObject
* @param propertyName
* @param propertyValue
* @param path
* @return string having JSON of the fragment/ form
* @pad.exclude Exclude from Published API.
*/
public static String findJsonObjectWithProperty(JSONObject jsonObject, String propertyName, String propertyValue, String path) {
return findJsonObjectWithProperty(jsonObject, propertyName, propertyValue, path, Boolean.FALSE);
}
/**
* @param templateId
* @param html
* @return HTML {@link String} of the templateId provided
* @pad.exclude Exclude from Published API.
* Returns the HTML of lazy asset from the whole AF HTML
*/
public static String getAssetHTMLFromFullHTML(String templateId, String html) {
return GuideHTMLParser.getAssetHTMLFromFullHTML(html, templateId);
}
/**
* @param json
* @param html
* @return String form of JSON object having asset JSON & asset HTML
* @pad.exclude Exclude from Published API.
*
* Forms a json object of the json and html strings provided
*/
public static String formJsonHtmlString(String json, String html, String multipleJson) {
StringWriter stringWriter = new StringWriter();
CustomJSONWriter jsonWriter = new CustomJSONWriter(stringWriter);
jsonWriter.object();
jsonWriter.key("json").value(json);
jsonWriter.key("html").value(html);
jsonWriter.key("multipleJson").value(multipleJson);
jsonWriter.endObject();
return stringWriter.toString();
}
/**
* @param guideContainer
* @return fetchs layout script from {@link com.adobe.aemds.guide.common.GuideContainer}
* @pad.exclude Exclude from Published API.
*
* Fetchs layout script from {@link com.adobe.aemds.guide.common.GuideContainer}
*/
public static String getLayoutScriptFromContainer(GuideContainer guideContainer) {
// get layout script from guideContainer
// getResource will take care of /libs and /apps
String script = guideContainer.getLayout();
Resource scriptResource = GuideUtils.getResolverFromResource(guideContainer).getResource(script);
String scriptPath;
if (scriptResource != null) {
scriptPath = scriptResource.getPath();
} else {
// where resolver cant resolve the resource (Test cases)
//fall back to hard-coded libs
scriptPath = "/libs" + "/" + script;
}
script = scriptPath + "/" + StringUtils.substringAfterLast(script, "/") + ".jsp";
return script;
}
/**
* @param guideContainer
* @param slingHttpServletResponse
* @return HTML of Adaptive Form (stringfied)
* @pad.exclude Exclude from Published API.
*
* Produce HTML of the children of {@link com.adobe.aemds.guide.common.GuideContainer}
*/
public static String produceHTML(GuideContainer guideContainer,
SlingHttpServletResponse slingHttpServletResponse) {
String script = GuideUtils.getLayoutScriptFromContainer(guideContainer);
SlingHttpServletRequest slingRequest = guideContainer.getSlingRequest();
try {
String guideContainerPath = guideContainer.getPath();
String urlToRootPanel = guideContainerPath +
"/" + GuideConstants.ROOTPANEL_NODENAME + "." + GuideConstants.HTML;
RequestDispatcher dispatcher = slingRequest.getRequestDispatcher(urlToRootPanel);
WCMMode.DISABLED.toRequest(slingRequest);
GuideStringWriterResponse responseWrapper = new GuideStringWriterResponse(slingHttpServletResponse);
dispatcher.include(new SlingHttpServletRequestWrapper(slingRequest), responseWrapper);
return responseWrapper.getString();
} catch (Exception e) {
logger.error("Error while executing script " + script, e);
}
return null;
}
/**
* @param guideJsonObject
* @param jsonArray
* @pad.exclude Exclude from Published API.
* Gets stringfied jsonModel object of the given templateId list
*/
public static String getJsonObjectWithGivenTemplateIds(JSONObject guideJsonObject, JSONArray jsonArray) {
try {
JSONObject jsonObject = new JSONObject();
for (int index = 0; index < jsonArray.length(); index++) {
JSONObject newGuideJsonObject = new JSONObject(guideJsonObject.toString());
String templateId = jsonArray.getString(index);
jsonObject.put(templateId, findJsonObjectWithProperty(newGuideJsonObject, GuideConstants.TEMPLATEID, templateId, "", Boolean.TRUE));
}
return jsonObject.toString();
} catch (Exception e) {
logger.error("Could not for json object with the given template ids", e);
}
return null;
}
/**
* Gets the JavaScript as String from the client lib path specified.
*
* @param htmlLibraryManager HtmlLibraryManager service.
* @param clientLibPath String specifying the path of client lib.
* @return String representing the java script code of the client lib(not css).
*/
public static String getScriptAsStringFromClientLib(HtmlLibraryManager htmlLibraryManager, String clientLibPath, boolean minify) {
StringWriter writer = new StringWriter();
InputStream inputStream = null;
try {
HtmlLibrary htmlLibrary = htmlLibraryManager.getLibrary(LibraryType.JS, clientLibPath);
if (htmlLibrary != null) {
inputStream = htmlLibrary.getInputStream(minify);
IOUtils.copy(inputStream, writer);
}
} catch (IOException ex) {
logger.error(ex.getMessage(), ex);
} finally {
IOUtils.closeQuietly(inputStream);
}
return writer.toString();
}
/**
* Gets the JavaScript as a string array from clientlib categories.
*
* @param htmlLibraryManager HtmlLibraryManager service.
* @param clientLibCategories Array of all clientlib categories fow which script is required.
* @return List of Strings for every clientlib specified.
*/
public static ArrayList getScriptFromClientLibList(HtmlLibraryManager htmlLibraryManager, String[] clientLibCategories, boolean minify) {
// Construct all the client libs here
// Order is important
// Get all the JS Files used by Adaptive form using the HTML library manager
Collection clientLibrary = htmlLibraryManager.getLibraries(clientLibCategories, null, true, false);
ArrayList script = new ArrayList();
// Walk through all the client libs and put it in rhino context
Iterator iter = clientLibrary.iterator();
while (iter.hasNext()) {
String path = ((ClientLibrary) iter.next()).getPath();
script.add(getScriptAsStringFromClientLib(htmlLibraryManager, path, minify));
}
return script;
}
/**
* Need an object like
* {
* "languages":[
* {"lang":"ja","dicts":["/libs/wcm/core/i18n/ja.json","path":"/libs/wcm/core/i18n/ja2.json"]},
* {"lang":"fr","dicts":["/libs/wcm/core/i18n/fr.json","/libs/wcm/core/i18n/fr2.json"]},
* {"lang":"de","dicts":[ /libs/wcm/core/i18n/de.json","path":"/libs/wcm/core/i18n/de2.json"]}
* ]
* }
*
* @param assetList
* @param locales
* @pad.exclude Exclude from published API
* Returns
*/
public static JSONObject getDictionaryInfoFromAssetPaths(JSONArray assetList, List locales) {
JSONObject dictionaryInfo = new JSONObject();
JSONArray dictInfoArray = new JSONArray();
try {
for (String locale : locales) {
JSONObject localeObject = new JSONObject();
localeObject.put(GuideConstants.LANG, locale);
JSONArray pathArray = new JSONArray();
for (int index = 0; index < assetList.length(); index++) {
String path = assetList.getString(index);
String convertedPath = convertContainerPathToDictionaryPath(path, locale);
if (StringUtils.isNotEmpty(convertedPath)) {
pathArray.put(convertedPath);
}
}
localeObject.put(GuideConstants.DICTS, pathArray);
dictInfoArray.put(localeObject);
}
dictionaryInfo.put(GuideConstants.LANGUAGES, dictInfoArray);
} catch (Exception e) {
logger.error("Could not create dictionary paths", e);
}
return dictionaryInfo;
}
private static String convertContainerPathToDictionaryPath(String containerPath, String locale) {
if (StringUtils.isNotEmpty(containerPath) && StringUtils.isNotEmpty(locale)) {
return containerPath + "/" + GuideConstants.ASSETS_NODE + "/" +
GuideConstants.DICTIONARY_NODENAME + "/" +
locale;
}
return null;
}
/**
*
* @param componentType
* @return
* @pad.exclude Exclude from Published API.
*/
public static String getDefaultPattern(String componentType) {
if (componentType.equals(GuideConstants.GUIDE_FIELD_EMAIL))
return GuideConstants.GUIDE_FIELD_EMAIL_PATTERN;
return "";
}
/**
*
* @param jsonData
* @return
* @throws JSONException
* @pad.exclude
*/
public static JSONObject getCCRData(String jsonData) throws JSONException{
if(jsonData != null && jsonData.length() > 0){
JSONObject jsonDataObj = new JSONObject(jsonData);
if(jsonDataObj.has(GuideConstants.WRAPPED_SUBMIT_JSON_ROOT)){
JSONObject jsonRoot = jsonDataObj.optJSONObject(GuideConstants.WRAPPED_SUBMIT_JSON_ROOT);
if(jsonRoot.has(GuideConstants.WRAPPED_SUBMIT_SUBMISSION_INFO_ROOT)){
JSONObject submissionInfoRoot = jsonRoot.optJSONObject(GuideConstants.WRAPPED_SUBMIT_SUBMISSION_INFO_ROOT);
if(submissionInfoRoot.has(GuideConstants.WEB_CHANNE_CCR_DATA_ROOT)){
JSONObject iccData = submissionInfoRoot.optJSONObject(GuideConstants.WEB_CHANNE_CCR_DATA_ROOT);
return iccData;
}
}
}
}
return null;
}
/**
* Checks case-insensitively if a string is present in a list of strings
* @param list
* @param searchString
* @param ignoreCase
* @pad.exclude Exclude from Published API.
*/
public static Boolean listContains(List list, String searchString, Boolean ignoreCase) {
if (searchString != null && list != null) {
if (!ignoreCase) {
return list.contains(searchString);
}
for (String str : list) {
if (searchString.equalsIgnoreCase(str)) {
return Boolean.TRUE;
}
}
}
return Boolean.FALSE;
}
/**
* Returns {@link org.apache.sling.api.scripting.SlingBindings} from given {@link org.apache.sling.api.SlingHttpServletRequest}
*
* @param slingRequest
* @return {@link org.apache.sling.api.scripting.SlingBindings}
* @pad.exclude Exclude from Published API.
*/
public static SlingBindings getSlingBinding(SlingHttpServletRequest slingRequest) {
SlingBindings bindings = null;
if (slingRequest != null) {
bindings = (SlingBindings) slingRequest.getAttribute(SlingBindings.class.getName());
}
return bindings;
}
/**
* This API check if the given resource is a form
* by looking for resource type property of jcr:content/guideContainer
*
* @param resource resource pointing to the page
* @return boolean Indicating if the given page is a form or not
*/
public static boolean checkIfForms(Resource resource) {
Resource pageContent = resource.getChild(GuideConstants.JCR_CONTENT_NODENAME);
if (pageContent != null) {
// check if there is a child node of name "guideContainer"
Resource guideContainer = pageContent.getChild(GuideConstants.GUIDECONTAINER_NODENAME);
if (guideContainer != null) {
// there can be use-case where guideContainer can be locked, in case of editable templates
// generally this is not a correct use-case, hence logging the same and ensuring form editor loads
Resource guideContainerMergedResource = guideContainer.adaptTo(TemplatedResource.class);
if (guideContainerMergedResource == null) {
// guide container is present inside initial content of editable template or inside static template
guideContainerMergedResource = guideContainer;
} else {
logger.warn("GuideContainer resource has been locked in the editable template for the form - " + resource.getPath());
}
// check if the given resource is a container resource of forms
return GuideConstants.CONTAINER_RESOURCES.contains(guideContainerMergedResource.getResourceType());
} else {
// if guide container is not present as a child, it may be part of structure aspect of a template
// in that case we need to move from page to template and from template to structure
Page currentPage = resource.adaptTo(Page.class);
if (currentPage != null) {
Template template = currentPage.getTemplate();
if (template == null) {
return false;
}
if (template.hasStructureSupport()) {
Resource res = pageContent.adaptTo(TemplatedResource.class);
if (res == null) {
// if there is no templated resource, return false
return false;
}
Iterator it = res.listChildren();
while (it.hasNext()) {
Resource child = it.next();
// check if the resource "r" is a guide container
String name = child.getName();
if (GuideConstants.GUIDE_CONTAINER_NODE_NAME.equals(name)) {
logger.warn("GuideContainer resource has been locked in the editable template for the form - " + resource.getPath());
// check if the guide container type has the container resource type
return GuideConstants.CONTAINER_RESOURCES.contains(child.getResourceType());
}
}
}
}
}
}
return false;
}
/**
* @pad.exclude Exclude from Published API.
*/
public static Resource getMergedFormResource (ResourceResolver resolver, String formPath) {
Resource formResource = resolver.resolve(formPath);
if (ResourceUtil.isNonExistingResource(formResource)) {
return null;
}
if (!checkIfForms(formResource)) {
return null;
}
Page currentPage = formResource.adaptTo(Page.class);
if (currentPage == null) {
return formResource;
}
Template template = currentPage.getTemplate();
if (template != null && template.hasStructureSupport()) {
formResource = formResource.adaptTo(TemplatedResource.class);
}
return formResource;
}
/**
* This API check if the given resource(template) is a forms template
* by looking for guideComponentType property in jcr:content node of template
*
* @param resource
* @return true if the resource is an AEM Forms template, false otherwise
*/
public static boolean checkIfFormsTemplate(Resource resource) {
Resource templateContent = resource.getChild("jcr:content");
if (templateContent != null) {
// check if the property guideComponentType exist
ValueMap templateContentValueMap = templateContent.getValueMap();
String guideComponentType = templateContentValueMap.get(GuideConstants.FD_GUIDE_COMPONENT_TYPE, "");
if (guideComponentType != null && guideComponentType.length() > 0) {
return true;
}
}
return false;
}
/**
* @pad.exclude Exclude from published API
*/
public static boolean isRepeatable(JSONObject obj) {
// assume can be repeatable if it has max or min occurs prop
int maxOccur = obj.optInt(GuideConstants.MAX_OCCUR, 1),
minOccur = obj.optInt(GuideConstants.MIN_OCCUR, 1);
return minOccur != 1 || maxOccur != 1;
}
/**
* @pad.exclude Exclude from published API
*/
public static boolean isCompositeField(JSONObject obj) {
String objType = obj.optString(GuideConstants.GUIDE_NODE_CLASS, "");
return GuideConstants.GUIDE_COMPOSITE_FIELD_TYPES.contains(objType);
}
/**
* @pad.exclude Exclude from published API
*/
public static boolean isSubmitableField(JSONObject obj) {
String objType = obj.optString(GuideConstants.GUIDE_NODE_CLASS, "");
return GuideConstants.GUIDE_SUBMITABLE_FIELD_TYPES.contains(objType);
}
/**
* Returns true if type equals guideTextDraw or guideAdobeSignBlock
* @pad.exclude Exclude from published API
*/
public static boolean isStaticTextType(String type) {
return GuideConstants.GUIDE_FIELD_TEXTDRAW.equals(type)
|| GuideConstants.GUIDE_FIELD_ADOBE_SIGN_BLOCK.equals(type);
}
/**
* Returns true if type equals guideTextDraw or guideAdobeSignBlock and have document fragment
* variables inside it
* @pad.exclude Exclude from published API
*/
public static boolean hasFloatingField(JSONObject obj) {
Boolean isFloatingField = Boolean.FALSE;
String objType = obj.optString(GuideConstants.GUIDE_NODE_CLASS, "");
if (GuideUtils.isStaticTextType(objType)) {
JSONArray documentFragmentVariables = obj.optJSONArray(GuideConstants.DOCUMENT_FRAGMENT_VARIABLES);
if (documentFragmentVariables != null && documentFragmentVariables.length() > 0) {
isFloatingField = Boolean.TRUE;
}
}
return isFloatingField;
}
/**
* Checks if the given container resource is a deprecated AD or not
* @pad.exclude Exclude from published API
*/
public static Boolean isDeprecatedAD(Resource containerResource){
Boolean isDeprecatedAD = false;
if(containerResource != null) {
if(containerResource.isResourceType(GuideConstants.RT_GUIDE_DOCUMENT_CONTAINER)){
isDeprecatedAD = true;
} else if(containerResource.isResourceType(GuideConstants.RT_WEB_DOCUMENT_CONTAINER)){
isDeprecatedAD = false;
}
}
return isDeprecatedAD;
}
/**
* @pad.exclude Exclude from published API
*/
public static FileAttachmentWrapper findFileAttachment(List attachmentWrappers, String fileName) {
if (attachmentWrappers != null) {
for (FileAttachmentWrapper fileAttachmentWrapper : attachmentWrappers) {
if (StringUtils.equals(fileAttachmentWrapper.getFileName(), fileName)) {
return fileAttachmentWrapper;
}
}
}
return null;
}
/**
* @pad.exclude Exclude from published API
*/
public static Resource getFormResource(Resource otherResource, String fragRef) {
if (StringUtils.isNotBlank(fragRef) && otherResource != null) {
String path = GuideUtils.convertFMAssetPathToContainerPath(fragRef);
ResourceResolver resolver = otherResource.getResourceResolver();
return resolver.getResource(path);
}
return null;
}
/**
* @pad.exclude Exclude from published API
*/
public static Resource getFormBreakpointResource(ResourceResolver resolver, String formPath) {
Resource formResource = getMergedFormResource(resolver, formPath);
if (formResource == null) {
return null;
}
if(formResource.getChild(GuideConstants.JCR_CONTENT_NODENAME) == null) {
return null;
}
Resource jcrResource = formResource.getChild(GuideConstants.JCR_CONTENT_NODENAME);
if (jcrResource == null) {
return null;
}
Resource responsiveResource = jcrResource.getChild("cq:responsive");
if (responsiveResource == null) {
return null;
}
return responsiveResource.getChild("breakpoints");
}
/**
* @pad.exclude Exclude from published API
*/
public static JSONObject getFormJson(Resource formRes, GuideModelTransformer guideModelTransformer) {
JSONObject guideJson = null;
try {
//TODO: Should not be forced to fallback to default locale
Locale defaultFallBackLocaleObject = new Locale(GuideConstants.DEFAULT_FALLBACK_LOCALE);
guideJson = guideModelTransformer.exportGuideJsonObject(formRes, null, defaultFallBackLocaleObject);
} catch (GuideException e) {
logger.error("Failed to Fetch Form Json", e);
}
return guideJson;
}
/**
* @pad.exclude Exclude from published API
*/
private static Resource findGuideContainerFromPage(Resource resource) {
if (resource == null) {
return null;
}
if (GuideUtils.isGuideContainerResource(resource)) {
return resource;
}
Resource r = null;
Iterator t = resource.listChildren();
while (t.hasNext() && r == null) {
Resource child = t.next();
if (child != null && GuideUtils.isGuideContainerResource(resource)) {
return child;
} else {
r = findGuideContainerFromPage(child);
}
}
return r;
}
/**
* This function returns the Guide Container path from any resource in the adaptive form.
* Eg - if the resource is a header/footer that is outside the guideContainer, then it traverses up to the cq:page and then
* searches down from cq:page for guideContainer
* @pad.exclude Exclude from published API
*/
public static String getGuideContainerPathFromResource(SlingHttpServletRequest request, Resource resource) {
String path = null;
Resource pageResource = getPageResource(resource);
Resource guideContainer = findGuideContainerFromPage(pageResource);
if (guideContainer != null) {
path = guideContainer.getPath();
}
return path;
}
/**
* @param obj : guide json obj
* @return
* @pad.exclude Exclude from Published API.
*/
public static boolean isUnboundObj(JSONObject obj) {
String bindRef = obj.optString(GuideConstants.BIND_REF);
return StringUtils.isBlank(bindRef);
}
/**
* Returns the theme content path from Guide container resource
*
* @param guideContainerResource resource to the form container
* @return Path to theme content resource of theme associated with guide container.
*/
public static String getThemeContentRef(Resource guideContainerResource) {
ValueMap vmap = guideContainerResource.getValueMap();
String themeRef = vmap.get(GuideConstants.THEME_CLIENTLIB, String.class);
if (StringUtils.isNotEmpty(themeRef)) {
themeRef = themeRef + GuideThemeConstants.RELATIVE_PATH_JCR_CONTENT;
}
return themeRef;
}
/**
* Transform JSON into Resource.
*
* @param resourceResolver ResourceResolver to be set for resource being returned
* @param path path on which resource has to be mounted
* @param json input JSON which is to be transformed into resource
* @return Resource
* @pad.exclude Excluede from published API
*/
public static Resource getResource(ResourceResolver resourceResolver,
String path, JSONObject json) {
return getResource(resourceResolver, path, json, null);
}
/**
* Transform JSON into Resource.
*
* @param resourceResolver ResourceResolver to be set for resource being returned
* @param path path on which resource has to be mounted
* @param json input JSON which is to be transformed into resource
* @param parentResource parent resource of synthetic resource that is being generated.
* @return Resource
* @pad.exclude Excluede from published API
*/
public static Resource getResource(ResourceResolver resourceResolver,
String path, JSONObject json, Resource parentResource) {
return getResource(resourceResolver, path, json, parentResource, false);
}
/**
* Transform JSON into Resource.
*
* @param resourceResolver ResourceResolver to be set for resource being returned
* @param path path on which resource has to be mounted
* @param json input JSON which is to be transformed into resource
* @param parentResource parent resource of synthetic resource that is being generated.
* @param useNameAsResourceIdentifier use name of resource as the key during resoruce creation from json
* @return Resource
* @pad.exclude Excluede from published API
*/
public static Resource getResource(ResourceResolver resourceResolver,
String path, JSONObject json, Resource parentResource, boolean useNameAsResourceIdentifier) {
if (json == null) {
return new GuideValueMapResource(resourceResolver, path, null, new ValueMapDecorator(new HashMap()), parentResource);
}
String resourceType = JcrConstants.NT_UNSTRUCTURED;
if (json.has(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY)) {
resourceType = json.optString(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY);
} else if (json.has(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY)) {
resourceType = json.optString(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY);
}
Map map = new HashMap();
ValueMap valueMap = new ValueMapDecorator(map);
List children = new ArrayList();
Resource valueMapResource = new GuideValueMapResource(resourceResolver, path, resourceType, valueMap, children, parentResource);
try {
Iterator keys = json.keys();
while (keys.hasNext()) {
String key = keys.next();
Object value = json.get(key);
if (value instanceof JSONObject) {
String name = null;
if (useNameAsResourceIdentifier) {
// using name of json object to create a resource
// sometimes key can be random(for example, in multi channel document use-case)
name = ((JSONObject) value).optString(GuideConstants.NAME);
if (StringUtils.isBlank(name)) {
name = key;
}
} else {
// use key present in json as the name of the resource
name = key;
}
// populate children
Resource child = getResource(resourceResolver, path + "/" + name, (JSONObject) value, valueMapResource, useNameAsResourceIdentifier);
children.add(child);
} else if (value instanceof JSONArray) {
JSONArray array = ((JSONArray) value);
ArrayList
© 2015 - 2025 Weber Informatics LLC | Privacy Policy