
com.adobe.aemds.guide.common.GuideNode 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.common;
import com.adobe.aemds.guide.model.ResponsiveConfiguration;
import com.adobe.aemds.guide.service.GuideException;
import com.adobe.aemds.guide.utils.GuideConstants;
import com.adobe.aemds.guide.utils.GuideContainerThreadLocal;
import com.adobe.aemds.guide.utils.GuideFragmentHolder;
import com.adobe.aemds.guide.utils.GuideUtils;
import com.adobe.aemds.guide.utils.NodeStructureUtils;
import com.adobe.cq.sightly.WCMUsePojo;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.foundation.forms.FormsConstants;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ModifiableValueMap;
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.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingBindings;
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.jcr.resource.JcrResourceConstants;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.jcr.RepositoryException;
import javax.script.SimpleBindings;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* GuideNode is base class which every AEM form component inherits from.
* It abstracts the basic properties of each component(panel/field).Few are listed below:
*
* - Sling HTTP Servlet Request
*
- Resource
*
- Properties of the resource
*
* This provides basic getter's and setter's required to create/initialize and AEM Form Component.
*
*
* @since AEM 6.0
*/
@Model(
adaptables = SlingHttpServletRequest.class,
adapters = StyledFDField.class)
public class GuideNode extends WCMUsePojo implements Serializable, StyledFDField {
@Self
protected SlingHttpServletRequest slingRequest;
@SlingObject
protected Resource resource;
@ScriptVariable(name = "properties")
protected ValueMap resourceProps;
protected String id = null;
protected String clientLibRef = null;
protected String baseName=null;
protected String localeName=null;
protected I18n i18n = null;
protected Locale locale=null;
protected XSSAPI xssapi = null;
protected String error = null;
protected Map inlineStyles = null;
protected Logger logger = LoggerFactory.getLogger(GuideNode.class);
private static String DEFAULT_RESPONSIVE_CLASSES = "fd-col-lg-12 fd-col-md-12 fd-col-sm-12 fd-col-xs-12";
/**
* @throws Exception
*/
public void activate() throws Exception {
resourceProps = ResourceUtil.getValueMap(getResource());
id = NodeStructureUtils.getGuideNodeHtmlId(getResource());
// set the sling request
setSlingRequest(getRequest());
}
@PostConstruct
private void initModel() {
// this is written so that the same class could be used as WCM Use and also sling model
if(slingRequest != null && resource != null) {
SlingBindings existingBindings = (SlingBindings) slingRequest.getAttribute(SlingBindings.class.getName());
SimpleBindings bindings = new SimpleBindings();
bindings.putAll(existingBindings);
init(bindings);
}
}
/**
* Returns Responsive Configuration (cq:responsive) of AEM Forms Component.
* @return ResponsiveConfiguration representing cq:responsive of field / panel
*/
public ResponsiveConfiguration getResponsiveConfiguration() {
ResponsiveConfiguration responsiveConfiguration = null;
Resource resource = getResource();
if (resource != null) {
Resource responsiveResource = resource.getChild("cq:responsive");
if (responsiveResource != null) {
responsiveConfiguration = responsiveResource.adaptTo(ResponsiveConfiguration.class);
}
}
return responsiveConfiguration;
}
/**
* Returns CSS classes to be applied on field/panel, for honoring its responsive configurtion.
* @return String representing CSS responsive classes
*/
public String getResponsiveClasses() {
String responsiveClasses = DEFAULT_RESPONSIVE_CLASSES;
ResponsiveConfiguration responsiveConfiguration = getResponsiveConfiguration();
if (responsiveConfiguration != null) {
responsiveClasses = responsiveConfiguration.getResponsiveClasses();
}
return responsiveClasses;
}
/**
* Returns the field type of the AEM Forms Component
* @return String representing guide field type
*/
public String getGuideFieldType() {
return "";
}
/**
* Return the JSON string containing property map of an AEM form component which is to be used during author time.
* Say, a custom component, wants to provides its own author config JSON, its has to override this.
* @return String authoringConfig JSON string
*/
public String getAuthoringConfigJSON(){
Map authoringConfig = getAuthoringConfig();
JSONObject authoringConfigJson =new JSONObject(authoringConfig);
return authoringConfigJson.toString();
}
/**
* AuthoringConfig is a map populated only for authoring and it contains key value pairs that govern components behaviour.
* There may be a use case where one wants to access few list of properties of AEM form component during authoring, this
* API is built for this.
* @return Map authoringConfig Map
*/
public Map getAuthoringConfig(){
Map authoringConfig = new HashMap();
int colspan= getColspan();
String inlineCssClass = getInlineCssClass();
String title = getTitle();
String enabled = getEnabled(),
visible = getVisible();
authoringConfig.put(GuideConstants.LAYOUT_COLSPAN,colspan);
// title is used in touch authoring to show parent hierarcy
authoringConfig.put(GuideConstants.TITLE_NODENAME," ".equals(title) ? getName() : title);
authoringConfig.put(GuideConstants.NAME, getName());
if(!inlineCssClass.isEmpty()) {
authoringConfig.put(GuideConstants.INLINE_CLASS_NAME, inlineCssClass);
}
/* enabled and visible is used in touch authoring dialog to submit
* default values for these properties in unchecked state only if value is
* defined on node structure..*/
if (enabled != null) {
authoringConfig.put(GuideConstants.ENABLED_GUIDE_PROPERTY, enabled);
}
if (visible != null) {
authoringConfig.put(GuideConstants.VISIBLE_GUIDE_PROPERTY, visible);
}
return authoringConfig;
}
/**
* Checks if the path is absolute. This API is written to support backward compatibility for forms developed over 6.0.
* In 6.1, we have introduced the notion of overlay, hence this API makes sure if any property of a node
* present in 6.0 form has an absolute path. Currently, this is used for field layout and autoSave strategy.
* @pad.exclude
*/
public boolean checkIfPathIsAbsolute(String path){
if((StringUtils.startsWith(path, "/libs") || StringUtils.startsWith(path, "/apps")) && StringUtils.endsWith(path, ".jsp")){
return true;
}
return false;
}
/**
* Returns the appearance of the widget configured during authoring.
* @return String representing path of appearance
*/
public String getAppearance() {
return resourceProps.get("appearance", "");
}
/**
* Returns the string containing the width and height property represented as an inline CSS rule.
* @return string containing width and height as inline CSS styl
*/
public String getStyles() {
String style = "";
String width = getWidth();
String height = getHeight();
// Append all styles here, for now only width is getting updated
style += ((width.length()) > 0 ? ("max-width:" + width + "%;") : (""));
style += ((height.length()) > 0 ? ("height:" + height + "px;") : (""));
// Return the style
return style;
}
public String getInlineStyles(String name) {
if (inlineStyles == null) {
inlineStyles = new HashMap();
String[] test = new String[]{""};
String[] inlineStylesProperties = resourceProps.get("inlineStyles", test);
if (!("".equals(inlineStylesProperties[0]))) {
for (int i = 0; i < inlineStylesProperties.length; i++) {
String componentProperties = inlineStylesProperties[i].substring(inlineStylesProperties[i].indexOf("{") + 1, inlineStylesProperties[i].indexOf("}"));
componentProperties = componentProperties.replace(',', ';');
String prefix = inlineStylesProperties[i].substring(0, inlineStylesProperties[i].indexOf("{"));
if (GuideConstants.GUIDE_STYLE_FIELD.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_FIELD, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_PANEL.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_PANEL, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_PANELDESCRIPTION.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_PANELDESCRIPTION, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_WIDGET.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_WIDGET, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_CAPTION.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_CAPTION, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_QUESTIONMARK.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_QUESTIONMARK, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_SHORTDESCRIPTION.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_SHORTDESCRIPTION, componentProperties);
} else if (GuideConstants.GUIDE_STYLE_LONGDESCRIPTION.equalsIgnoreCase(prefix)) {
inlineStyles.put(GuideConstants.GUIDE_STYLE_LONGDESCRIPTION, componentProperties);
}
}
}
}
return inlineStyles.get(name);
}
public String getFieldInlineStyles() {
return getInlineStyles(GuideConstants.GUIDE_STYLE_FIELD);
}
public String getQuestionMarkInlineStyles() {
return getInlineStyles(GuideConstants.GUIDE_STYLE_QUESTIONMARK);
}
public String getLongDescriptionInlineStyles() {
return getInlineStyles(GuideConstants.GUIDE_STYLE_LONGDESCRIPTION);
}
/**
* Returns the colspan of an AEM form component configured during authoring.
* This holds valid only in case of AEM form field's whose parent has a grid fluid layout configured.
* Col Span indicates the number of columns an AEM Form component should span across
* @return integer representing the colspan
*/
public Integer getColspan(){
return Integer.parseInt(resourceProps.get("colspan", "1"));
}
/**
* Returns the inline CSS class applied to the component during style authoring.
* @return String representing the CSS class name
*/
public String getInlineCssClass() {
return resourceProps.get("cq:cssClass", "");
}
/**
* Returns the height of AEM Form component configured in the authoring dialog.
* The value returned has pixel as its unit.
* @return String representing the height
*/
public String getHeight(){
// Expected that width should be in px in CQ Dialog
return resourceProps.get("height", "");
}
/**
* Returns the width of AEM Form Component configured in the authoring dialog.
* The value returned has percentage as its unit
* @return width of the form component
*/
public String getWidth(){
// Expected that width should be in % in CQ Dialog
return resourceProps.get(GuideConstants.WIDTH, "");
}
/**
* Returns the specification version of Adaptive Form Component
* Version of an adaptive form component specifies the node structure changes.
* @return String representing the adaptive form component's specification version
*/
public String getVersion() {
return resourceProps.get(GuideConstants.FD_VERSION, GuideConstants.LEGACY_AF_SPEC_VERSION);
}
/**
* Returns the target specification version of Adaptive Form Component.
* Target version of an Adaptive form component specifies the behaviour/rendition of the component.
* @return String representing the adaptive form component's target specification version
*/
public String getTargetVersion() {
return resourceProps.get(GuideConstants.FD_TARGET_VERSION, GuideConstants.LEGACY_AF_TARGET_SPEC_VERSION);
}
/**
* Set's the sling resource for the given AEM Form Component.
* @param resource Represents the resource to be used
* @see Resource
* @deprecated use the init API
*/
public void setResource(Resource resource) {
SimpleBindings bindings = new SimpleBindings();
bindings.put("resource",resource);
init(bindings);
}
/**
* Set's the sling resource for the given AEM Form Component.
* @param slingRequest Represents the http sling request
* @see SlingHttpServletRequest
*/
public void setSlingRequest(SlingHttpServletRequest slingRequest) {
this.slingRequest = slingRequest;
try {
GuideFragmentHolder guideFragmentHolder = GuideContainerThreadLocal.getGuideFragmentHolder();
// See if it is the case where we need to change Resource bundle
if (guideFragmentHolder != null) {
i18n = guideFragmentHolder.getI18n();
if (i18n == null) {
if (slingRequest != null) {
// fall back as adaptive form's resource bundle
i18n = GuideUtils.getI18n(slingRequest, getResource());
}
}
} else if (slingRequest != null) {
i18n = GuideUtils.getI18n(slingRequest, getResource());
}
} catch (Exception e) {
logger.error("Error in setting sling request in guide node", e);
}
}
public String getEnabledExp() {
return resourceProps.get("enabledExp", "");
}
public String getName(){
//TODO: Why StringEscapeUtils?
return StringEscapeUtils.escapeHtml4(NodeStructureUtils.getGuideName(getResource()));
}
public String getDescription(){
return externalize(resourceProps.get(JcrConstants.JCR_DESCRIPTION, ""));
}
public String getXssDescription() {
return i18n.getVar(this.getDescription()); //TODO: XssDescription return i18n instead
}
public String getId() throws RepositoryException {
return id;
}
/**
* Utility to check if the AEM Form Component is rendered during edit/design mode of AEM.
* @return boolean representing if the given mode is edit/design or not
*/
public Boolean getIsEditMode() {
return WCMMode.fromRequest(slingRequest) == WCMMode.EDIT ||
WCMMode.fromRequest(slingRequest)== WCMMode.DESIGN;
}
/**
* Utility to check if the given AEM Form Component is repeatable or not
* @return boolean represent if repeatable or not
*/
public boolean getIsRepeatable() {
return false;
}
/**
* Returns the list of items present inside an AEM Forms container
* @return List of {@link GuideNode} present inside the container
*/
public List getItems() {
return new ArrayList();
}
/**
* Returns the path representing the current AEM Form Component. This path
* is the JCR Path of the current resource.
* @return string representing the path
*/
public String getPath(){
return getResource().getPath();
}
/**
* Returns the sling resource type of the current resource set.
* @return string representing the resource type
*/
public String getResourceType(){
return getResource().getResourceType();
}
/**
* Returns the sling resource super type of the current resource set.
* @return string representing the resource super type
*/
public String getResourceSuperType(){
return getResource().getResourceSuperType();
}
/**
* Returns the path of the layout configured in an AEM Form Panel
* @return String representing path of the layout
* @throws PersistenceException
*/
public String getLayoutPath() throws PersistenceException {
return (String)getLayoutProperty(GuideConstants.SLING_RESOURCE_TYPE);
}
/**
* Returns the nonNavigable property of the layout.
* Till 6.2, nonNavigable property was stored as a string. In 6.3, this property is now stared as boolean.
* This function gets the nonNavigable property and converts it into a boolean and returns it.
* @return Boolean
* @pad.exclude
*/
public Boolean getNonNavigableProperty(){
Boolean nonNavigable = Boolean.FALSE;
try {
Object nonNavigableLayoutPropertyValue = getLayoutProperty(GuideConstants.LAYOUT_NON_NAVIGABLE_PROPERTY);
if(nonNavigableLayoutPropertyValue == null){
Map layoutproperties = NodeStructureUtils.getLayoutProperties(this.slingRequest,
getResource(), NodeStructureUtils.PANEL_NODENAME);
// to support BC for forms created before 6.4, checking if layout is gridFluidLayout, then explicitly adding nonNavigable as true
Object resourceType = layoutproperties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY);
String resourceTypeAsString = null;
if(resourceType != null){
resourceTypeAsString = resourceType.toString();
}
// for gridFluidLayout, non-navigable property would be true
if(StringUtils.isNotBlank(resourceTypeAsString) &&
(StringUtils.equals(resourceTypeAsString, GuideConstants.LAYOUT_GRIDFLUIDLAYOUT) ||
StringUtils.equals(resourceTypeAsString, GuideConstants.LAYOUT_GRIDFLUIDLAYOUT2))){
nonNavigable = Boolean.TRUE;
}
}
else if (nonNavigableLayoutPropertyValue instanceof String) {
nonNavigable = Boolean.parseBoolean((String) nonNavigableLayoutPropertyValue);
} else {
nonNavigable = (Boolean)nonNavigableLayoutPropertyValue;
}
} catch (Exception e){
logger.error("AF: Unable to fetch nonNavigable property"+ e.getMessage(), e);
}
return nonNavigable;
}
/**
* Checks if the layout configured in the AEM Forms Panel component is navigable.
* @return boolean indicating if layout is navigable
* @throws PersistenceException
*/
public boolean isLayoutNavigable() throws PersistenceException {
Boolean nonNavigableProp = getNonNavigableProperty();
if(nonNavigableProp == null) {
// The fallback only to support the existing guides and not break them.
String layoutPath = GuideUtils.getNormalizedNodeType(getLayoutPath(), null);
if(GuideConstants.LAYOUT_GRIDFLUIDLAYOUT.equals(layoutPath) ||
GuideConstants.LAYOUT_GRIDFLUIDLAYOUT2.equals(layoutPath)) {
nonNavigableProp = true;
} else {
nonNavigableProp = false;
}
}
return !nonNavigableProp;
}
/**
* Returns true for guide node type or super type being rootPanel / panel / guideAdModule / guideAdModuleGroup
* @return true, if menu required for the component else false
*/
public boolean isMenuRequired() {
Resource res = getResource();
String normalizedResourceType = GuideUtils.getNormalizedNodeType(getResourceType(), getResourceSuperType());
if (GuideConstants.MOBILE_MENU_RESOURCES.contains(normalizedResourceType)) {
return true;
} else if(res != null && res.isResourceType(GuideConstants.RT_PANEL)){
// any resource type inheriting from panel, should contain menu in mobile
return true;
}
return false;
}
/**
* Returns true for guide node type or super type is guideAdModuleGroup
* @return true if component is part of document fragment group else false
* @deprecated
*/
public boolean isDocumentFragmentGroup() {
String normalizedResourceType = GuideUtils.getNormalizedNodeType(getResourceType(), getResourceSuperType());
if (GuideConstants.RT_MODULE_GROUP.equals(normalizedResourceType) || GuideConstants.RT_WEB_DOCUMENT_TARGET_AREA.equals(normalizedResourceType)) {
return true;
}
return false;
}
protected Object getLayoutProperty(String property) throws PersistenceException {
Map layoutproperties = NodeStructureUtils.getLayoutProperties(this.slingRequest,
getResource(), NodeStructureUtils.PANEL_NODENAME);
if(layoutproperties != null) {
return layoutproperties.get(property);
}
return null;
}
/***
* @throws PersistenceException
* @pad.exclude Exclude from Published API.
*/
public String getLayoutTabType() throws PersistenceException {
String tabType = (String)getLayoutProperty(GuideConstants.LAYOUT_TAB_TYPE_PROPERTY);
if(tabType == null) {
// The fallback only to support the existing guides and not break them.
String layoutPath = GuideUtils.getNormalizedNodeType(getLayoutPath(), null);
if(GuideConstants.LAYOUT_WIZARDLAYOUT.equals(layoutPath)) {
tabType = "wizard-tab";
} else {
tabType = "tab";
}
}
return tabType;
}
public String getToolbarPosition() throws PersistenceException {
Map layoutproperties = NodeStructureUtils.getLayoutProperties(this.slingRequest, getResource(), NodeStructureUtils.PANEL_NODENAME);
if (layoutproperties != null) {
String layout = (String) layoutproperties.get(GuideConstants.TOOLBAR_POSITION);
if (StringUtils.isNotEmpty(layout)) {
return layout;
}
}
return GuideConstants.TOOLBAR_POSITION_BOTTOM;
}
public String getAddMessage() {
String add = i18n.get("Add ");
return add + this.getNavTitle();
}
public String getRemoveMessage() {
String add = i18n.get("Remove ");
return add + this.getNavTitle();
}
public String getNavTitle() {
return externalize(resourceProps.get("navTitle", this.getTitle()));
}
/**
* Returns the title of the AEM Form component.
* @return String representing the title
*/
public String getTitle() {
return externalize(resourceProps.get(JcrConstants.JCR_TITLE," "));
}
/**
* Returns the Interface to provide client request information to a servlet.
* @return sling http request
*/
public SlingHttpServletRequest getSlingRequest() {
return slingRequest;
}
/**
* Returns the node class associated with the of the AEM form component. This node class is
* used to instantiate client model
* @return String representing the node class
*/
public String getNodeClass() {
return resourceProps.get(GuideConstants.ELEMENT_PROPERTY_NODECLASS, "");
}
public String getVisibleExp() {
return resourceProps.get("visibleExp", "");
}
public XSSAPI getXssapi() {
if (slingRequest != null) {
return slingRequest.adaptTo(XSSAPI.class);
} else {
return null;
}
}
/**
* Returns the name of the CSS class configured during authoring.
* @return String representing the CSS class name
*/
public String getCssClassName() {
return resourceProps.get(FormsConstants.ELEMENT_PROPERTY_CSS, "");
}
public String externalize(String key) {
//if author mode return key
boolean editMode = WCMMode.fromRequest(slingRequest) == WCMMode.EDIT || WCMMode.fromRequest(slingRequest)== WCMMode.DESIGN;
if(editMode)
return key;
if (key == null || "".equals(key)) {
return null;
}
return GuideUtils.translateOrReturnOriginal(key, i18n);
}
public String getError() {
return error;
}
public String getBindRef() {
return (String)resourceProps.get("bindRef");
}
private String getXDPJSON(String bindref) {
ResourceResolver resourceResolver = getResource().getResourceResolver();
Resource guideContainerResource = resourceResolver
.getResource(GuideUtils.getGuideContainerPath(slingRequest, getResource()));
ValueMap map = ResourceUtil.getValueMap(guideContainerResource);
boolean refersXDP = map.get("xdpRef") != null;
boolean refersXSD = map.get("xsdRef") != null;
if(bindref == null ) {
return null;
}
if(refersXSD) {
return "xsd";
}
if(!refersXDP) {
return "";
}
Resource assetsResource = resourceResolver.getResource(guideContainerResource, "assets/xfaObjects");
if(assetsResource != null) {
ValueMap xfaObjects = ResourceUtil.getValueMap(assetsResource);
return (String) xfaObjects.get(bindref);
}
return null;
}
/*
* returns true if the xdpRef property is not present in Guide or bindRef property is null.
* otherwise checks the map (at assets/xfaObjects) for the value of bindref property
* returns true if the attribute is present otherwise false
*/
public boolean isValid() {
String bindref = getBindRef();
if(bindref != null ) {
String json = getXDPJSON(bindref);
if("xsd".equals(json)){
return true;
}
if(json == null) {
I18n i18n = new I18n(slingRequest);
String e1 = i18n.get("NoSuchSOMExpression: bindRef (");
String e2 = i18n.get(") provided doesn't point to an valid element in XDP.");
error = e1 + bindref + e2;
return false;
}
return true;
}
return true;
}
private boolean isPropertySame(Object oldProp, Object newProp) throws JSONException {
if(oldProp == null && newProp == null) {
return true;
} else if(oldProp == null) {
return false;
} else if(newProp == null) {
return false;
} else {
if(oldProp instanceof JSONArray && newProp instanceof String[]) {
JSONArray sop = (JSONArray) oldProp;
String[] snp = (String[]) newProp;
if(sop.length() != snp.length) {
return false;
} else {
boolean flag = true;
for (int i = 0; i < sop.length(); i++) {
flag = flag && sop.get(i).equals(snp[i]);
}
return flag;
}
} else {
return oldProp.equals(newProp);
}
}
}
private ArrayList getModifiedXfaProps(JSONObject oldXfaProps) {
ArrayList props = new ArrayList();
if(oldXfaProps != null) {
String prop = null;
try {
Iterator propIterator = oldXfaProps.keys();
while(propIterator.hasNext()) {
prop = propIterator.next();
if(isPropertySame(oldXfaProps.get(prop), resourceProps.get(prop) )) {
logger.info("AEMAF unmodified property in Guide "+prop);
props.add(prop);
}
}
} catch (JSONException e) {
logger.error("AEMAF error in accessing old properties " + e.getMessage() +
" old property " + prop, e);
}
} else {
logger.error("AEMAF xfajson attribute not present in the node " + getResource().getPath());
}
return props;
}
private void syncProp(String prop, Object newJSONVal,
ModifiableValueMap modifiableResourceProps) throws JSONException {
Object newVal = newJSONVal;
if(newJSONVal instanceof JSONArray) {
JSONArray newJSONArr = (JSONArray) newJSONVal;
Object[] list = new Object[newJSONArr.length()];
for(int j = 0;j " + newVal+" ]");
}
}
private void syncProps(JSONObject bindNode, ArrayList unchangedProps,
JSONObject oldProps) throws JSONException {
Iterator newPropIterator = bindNode.keys();
ModifiableValueMap modifiableResourceProps = getResource().adaptTo(ModifiableValueMap.class);
while(newPropIterator.hasNext()) {
String prop = newPropIterator.next();
if(unchangedProps.contains(prop) || (!oldProps.has(prop) && !resourceProps.containsKey(prop))) {
syncProp(prop, bindNode.get(prop), modifiableResourceProps);
if(unchangedProps.contains(prop)) {
unchangedProps.remove(prop);
}
}
}
for(int i = 0;i < unchangedProps.size(); i++) {
String prop = unchangedProps.get(i);
syncProp(prop, null, modifiableResourceProps);
}
try {
modifiableResourceProps.put("xfajson" , bindNode.toString());
getResource().getResourceResolver().commit();
resourceProps = getResource().adaptTo(ValueMap.class);
} catch (PersistenceException e) {
logger.error("AEMAF Unable to commit changes for the node " + getResource().getPath(), e);
}
}
public void syncNode() throws GuideException {
String bindref = getBindRef();
String jsonString = (String)resourceProps.get("xfajson");
if(bindref != null && jsonString != null) {
try {
JSONObject oldXfaProps = new JSONObject(jsonString);
ArrayList unchangedProps = getModifiedXfaProps(oldXfaProps);
if(!unchangedProps.isEmpty()) {
String json = getXDPJSON(bindref);
if(json != null) {
try {
JSONObject bindNode = new JSONObject(json);
syncProps(bindNode, unchangedProps, oldXfaProps);
} catch (JSONException e) {
logger.error("AEMAF error in accessing new properties " + e.getMessage() + " properties " + json, e);
}
} else if("".equals(json)) {
//guide changed from xdp to xsd. we should remove xfajson.
} else {
logger.error("AEMAF unable to sync. Invalid SOM Reference in node " + bindref);
}
}
} catch (JSONException e) {
logger.error("AEMAF error in accessing old properties " + e.getMessage() +
" old properties " + jsonString, e);
throw new GuideException(e);
}
}
}
public boolean isValidDorTemplateRef() {
ResourceResolver resourceResolver = getResource().getResourceResolver();
Resource guideContainerResource = resourceResolver
.getResource(GuideUtils.getGuideContainerPath(slingRequest, getResource()));
ValueMap map = ResourceUtil.getValueMap(guideContainerResource);
String dorTemplateRef = null;
// now this DOR enabled for plain guides just check for dorTemplateRef property
return (dorTemplateRef = (String) map.get("dorTemplateRef")) != null && dorTemplateRef.length() > 0;
}
// for including custom client lib in fragment panel
public String getClientLibRef() {
return clientLibRef;
}
public void setClientLibRef(String clientLibRef) {
this.clientLibRef = clientLibRef;
}
/**
* @return Returns the value of "enabled" property of field.
*/
protected String getEnabled () {
return resourceProps.get("enabled", String.class);
}
/**
* @return Returns the value of "visible" property of field.
*/
protected String getVisible () {
return resourceProps.get("visible", String.class);
}
}