
com.adobe.cq.msm.ui.models.alllivecopies.LiveCopiesTable Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2016 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 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.cq.msm.ui.models.alllivecopies;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.jcr.RangeIterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.io.JSONStringer;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.Self;
import com.adobe.cq.wcm.launches.utils.LaunchUtils;
import com.adobe.granite.ui.components.Config;
import com.adobe.granite.ui.components.ExpressionHelper;
import com.adobe.granite.ui.components.ExpressionResolver;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.WCMException;
import com.day.cq.wcm.msm.api.BlueprintManager;
import com.day.cq.wcm.msm.api.LiveRelationship;
import com.day.cq.wcm.msm.api.LiveRelationshipManager;
import com.day.cq.wcm.msm.api.LiveStatus;
import com.day.cq.wcm.msm.api.MSMNameConstants;
@Model(adaptables = SlingHttpServletRequest.class)
public class LiveCopiesTable {
@Self
private SlingHttpServletRequest request;
private Resource resource;
private Resource rootResource;
private ResourceResolver resourceResolver;
private List rows;
private PageManager pageManager;
private LiveRelationshipManager relationMgr;
private BlueprintManager bpm;
private Map tableAttrbsMap;
private boolean tableExists;
private Map liveCopiesMap;
private Pattern excludePattern;
@ScriptVariable
private XSSAPI xssAPI;
@OSGiService
private ExpressionResolver expressionResolver;
private static HashMap statusDetailsMap = new HashMap();
private static final String MSM_STATUS_STNCHRONIZED= "msm-status-synchronized";
private static final String MSM_STATUS_SOURCE_MODIFIED = "msm-status-src-modified";
private static final String MSM_STATUS_TARGET_MODIFIED = "msm-status-target-modified";
private static final String MSM_STATUS_NEW = "msm-status-new";
private static final String MSM_STATUS_TARGET_DOES_NOT_EXIST = "msm-status-target-does-not-exist";
private static final String MSM_STATUS_CANCELLED = "msm-status-cancelled";
private static final String MSM_BLUEPRINT_EDIT_PAGE_ACTION = "cq-wcm-msm-all-live-copies-openpage-activator";
private static final String MSM_BLUEPRINT_ROLLOUT_ACTION = "cq-wcm-msm-all-live-copies-rollout-activator";
private static final String MSM_LIVECOPY_EDIT_PAGE_ACTION = "cq-wcm-msm-all-live-copies-openlivecopy-activator";
private static final String MSM_LIVECOPY_RELATIONSHIP_ACTION = "cq-wcm-msm-all-live-copies-relationship-activator";
private static final String MSM_LIVECOPY_SYNC_ACTION = "cq-wcm-msm-all-live-copies-sync-activator";
private static final String MSM_LIVECOPY_RESET_ACTION = "cq-wcm-msm-all-live-copies-reset-activator";
private static final String MSM_LIVECOPY_SUSPEND_ACTION = "cq-wcm-msm-all-live-copies-suspend-activator";
private static final String MSM_LIVECOPY_RESUME_ACTION = "cq-wcm-msm-all-live-copies-resume-activator";
private static final String MSM_LIVECOPY_DETACH_ACTION = "cq-wcm-msm-all-live-copies-detach-activator";
static {
// for localization
// i18n.get("LIVE COPY UP TO DATE");
// i18n.get("BLUEPRINT MODIFIED");
// i18n.get("LIVE COPY MODIFIED")
// i18n.get("LIVE COPY LOCALLY CREATED");
// i18n.get("LIVE COPY DOES NOT EXIST");
// i18n.get("INHERITANCE CANCELLED");
statusDetailsMap.put(MSM_STATUS_STNCHRONIZED, new StatusDetails("checkCircle", "cq-icon-green", "LIVE COPY UP TO DATE"));
statusDetailsMap.put(MSM_STATUS_SOURCE_MODIFIED, new StatusDetails("clock", "cq-icon-black", "BLUEPRINT MODIFIED"));
statusDetailsMap.put(MSM_STATUS_TARGET_MODIFIED, new StatusDetails("clock", "cq-icon-black", "LIVE COPY MODIFIED"));
statusDetailsMap.put(MSM_STATUS_NEW, new StatusDetails("addCircle", "cq-icon-black", "LIVE COPY LOCALLY CREATED"));
statusDetailsMap.put(MSM_STATUS_TARGET_DOES_NOT_EXIST, new StatusDetails("exclude", "cq-icon-grey", "LIVE COPY DOES NOT EXIST"));
statusDetailsMap.put(MSM_STATUS_CANCELLED, new StatusDetails("closeCircle", "cq-icon-red", "INHERITANCE CANCELLED"));
}
@PostConstruct
public void postConstruct() throws Exception {
this.resource = request.getResource();
this.resourceResolver = request.getResourceResolver();
relationMgr = resourceResolver.adaptTo(LiveRelationshipManager.class);
bpm = resourceResolver.adaptTo(BlueprintManager.class);
pageManager = resourceResolver.adaptTo(PageManager.class);
ExpressionHelper exp = new ExpressionHelper(expressionResolver, request);
Config cfg = new Config(resource);
String rootPath = StringUtils.trimToNull(request.getRequestPathInfo().getSuffix());
this.rootResource = resourceResolver.getResource(rootPath);
if (rootResource == null) {
tableExists = false;
return;
}
String filter = cfg.get("exclude", "");
excludePattern = Pattern.compile(filter);
tableExists = true;
String src = StringUtils.trimToNull(exp.getString(cfg.get("src", String.class)));
String layoutName = "foundation-layout-table";
String selectionCount = cfg.get("selectionCount", "multiple");
tableAttrbsMap = new HashMap();
tableAttrbsMap.put("data-foundation-collection-id", rootPath);
tableAttrbsMap.put("data-foundation-collection-src", src);
tableAttrbsMap.put("data-foundation-selections-mode", selectionCount);
tableAttrbsMap.put("data-foundation-mode-group", cfg.get("modeGroup", String.class));
tableAttrbsMap.put("data-foundation-layout-table-hasmore", "false");
String layoutJson = new JSONStringer()
.object()
.key("name").value(layoutName)
.key("sortMode").value(cfg.get("sortMode", String.class))
.key("layoutId").value(resource.getName()) // This is used as an id to identify the layout when there are multiple layouts to represent the same collection.
.endObject()
.toString();
tableAttrbsMap.put("class", cfg.get("granite:rel", "cq-wcm-msm-all-live-copies") + " foundation-layout-util-maximized-alt foundation-collection foundation-layout-table coral-Table-wrapper coral-Table-wrapper--sticky " + layoutName);
tableAttrbsMap.put("data-foundation-layout", layoutJson);
if ("multiple".equals(selectionCount)) {
tableAttrbsMap.put("multiple", selectionCount);
tableAttrbsMap.put("selectionMode", cfg.get("selectionMode", "none"));
}
tableAttrbsMap.put("selectable", "selectable");
RangeIterator rootRelations = relationMgr.getLiveRelationships(rootResource, null, null);
liveCopiesMap = getFilteredNames(rootRelations);
rows = new ArrayList();
Page requestedPage = pageManager.getPage(rootResource.getPath());
if (requestedPage == null) {
//resource is folder list only folder contains
Iterator resourceIterator = rootResource.getChildren().iterator();
while (resourceIterator.hasNext()) {
Resource currResource = resourceIterator.next();
String relSourcePath = getRelativeSourcePath(rootResource, currResource);
if ( !isResourceAcceptable(currResource)) {
continue;
}
Page currPage = pageManager.getPage(currResource.getPath());
if (currPage == null) {
//row represents a folder;
rows.add(new LiveCopiesRow(currResource.getPath(), currResource.getName(), relSourcePath));
} else {
String rowActionRels = getBlueprintActionRels(currResource, isResourceBlueprint(currResource));
String thumbnailPath = xssAPI.getValidHref(request.getContextPath() + getThumbnailUrl(currPage, 48, 48));
rows.add(new LiveCopiesRow(true, currResource.getPath(), currPage.getTitle(), Collections.emptyList(), thumbnailPath, rowActionRels, relSourcePath));
}
}
} else {
Iterator pageIter = requestedPage.listChildren();
while (pageIter.hasNext()) {
Page currPage = pageIter.next();
Resource currPageResource = resourceResolver.getResource(currPage.getPath());
String relSourcePath = getRelativeSourcePath(rootResource, currPageResource);
if ( !isResourceAcceptable(currPageResource)) {
continue;
}
String relPath = "";
if (currPage.getPath().startsWith(rootPath + "/")) {
relPath = currPage.getPath().substring(rootPath.length()+1);
}
String rowTitle = currPage.getTitle();
String rowPath = currPage.getPath();
String thumbnailPath = xssAPI.getValidHref(request.getContextPath() + getThumbnailUrl(currPage, 48, 48));
List cellInfo = new ArrayList();
Map cellAttrbs;
boolean isBlueprint = false;
for(String liveCopyPath : liveCopiesMap.keySet()) {
if ( !StringUtils.isEmpty(liveCopyPath)) {
cellAttrbs = new HashMap();
cellAttrbs.put("is", "coral-table-cell");
cellAttrbs.put("is", "coral-table-cell");
String currliveCopyPath = liveCopyPath + "/" + relPath;
String statusMesg = getStatus(relationMgr, currPageResource, currliveCopyPath);
if (!isBlueprint && bpm.getContainingBlueprint(currPageResource.getPath()) != null &&
statusMesg != MSM_STATUS_TARGET_DOES_NOT_EXIST) {
isBlueprint = true;
}
StatusDetails statusDetails = statusDetailsMap.get(statusMesg);
String cellActionRels = getLivecopyActionRels(statusMesg);
String relationshipDetailJson = new JSONStringer()
.object()
.key("source").value(currPage.getPath())
.key("target").value(currliveCopyPath)
.endObject()
.toString();
cellAttrbs.put("data-relationship", relationshipDetailJson);
cellAttrbs.put("data-actionrels", cellActionRels);
LiveCopiesCell allLiveCopiesCell = new LiveCopiesCell(statusDetails.getIconName(), statusDetails.getIconClass(), statusDetails.getStatusMessage(), cellAttrbs);
cellInfo.add(allLiveCopiesCell);
}
}
// root resource does not have live copies but current row resource might have
if (!isBlueprint && liveCopiesMap.isEmpty()) {
isBlueprint = isResourceBlueprint(currPageResource);
}
String rowActionRels = getBlueprintActionRels(currPageResource, isBlueprint);
rows.add(new LiveCopiesRow(true, rowPath, rowTitle, cellInfo, thumbnailPath, rowActionRels, relSourcePath));
}
}
}
private boolean isResourceAcceptable(Resource currResource) {
if (excludePattern.matcher(currResource.getPath()).matches()) {
return false;
} else if (pageManager.getPage(currResource.getPath()) != null) {
return true;
} else {
boolean isFolder = currResource.isResourceType("sling:Folder") ||
currResource.isResourceType("sling:OrderedFolder") ||
currResource.isResourceType(JcrConstants.NT_FOLDER);
return isFolder;
}
}
private boolean isResourceBlueprint(Resource currResource) throws WCMException {
if (bpm.getContainingBlueprint(currResource.getPath()) == null ||
!relationMgr.isSource(currResource)) {
return false;
}
RangeIterator relationships = relationMgr.getLiveRelationships(currResource, null, null);
while(relationships.hasNext()) {
LiveRelationship currRelationship = (LiveRelationship) relationships.next();
String lcPath = currRelationship.getLiveCopy().getPath();
if (!LaunchUtils.isLaunchResourcePath(lcPath)) {
// at least one is not a launch > condition true
return true;
}
}
return false;
}
private String getBlueprintActionRels(Resource currResource, boolean isBlueprint) {
String rowActionRels = MSM_BLUEPRINT_EDIT_PAGE_ACTION;
if (isBlueprint) {
rowActionRels = rowActionRels + " " + MSM_BLUEPRINT_ROLLOUT_ACTION;
}
return rowActionRels;
}
private String getLivecopyActionRels(String statusMesg) throws JSONException {
JSONArray actionRels = new JSONArray();
actionRels.put(MSM_LIVECOPY_EDIT_PAGE_ACTION);
actionRels.put(MSM_LIVECOPY_RELATIONSHIP_ACTION);
if (statusMesg.equals(MSM_STATUS_TARGET_DOES_NOT_EXIST)) {
} else if (statusMesg.equals(MSM_STATUS_CANCELLED)) {
actionRels.put(MSM_LIVECOPY_RESUME_ACTION)
.put(MSM_LIVECOPY_DETACH_ACTION);
} else {
actionRels.put(MSM_LIVECOPY_SYNC_ACTION)
.put(MSM_LIVECOPY_RESET_ACTION)
.put(MSM_LIVECOPY_SUSPEND_ACTION)
.put(MSM_LIVECOPY_DETACH_ACTION);
}
return actionRels.toString();
}
private String getThumbnailUrl(Page page, int width, int height) {
String ck = "";
ValueMap metadata = page.getProperties("image/file/jcr:content");
if (metadata != null) {
Calendar cal = metadata.get(JcrConstants.JCR_LASTMODIFIED, Calendar.class);
if (cal != null) {
ck = "" + (cal.getTimeInMillis() / 1000);
}
}
return Text.escapePath(page.getPath()) + ".thumb." + width + "." + height + ".png?ck=" + ck;
}
public String getPath() {
return this.resource.getPath();
}
public Map getColumns() {
return liveCopiesMap;
}
public List getRows() {
return rows;
}
public Map getTableAttrbs() {
return tableAttrbsMap;
}
public boolean tableExist() {
return tableExists;
}
public boolean hasChildren() {
if (rows.isEmpty()) {
return false;
}
return true;
}
public int columnsSize() {
return liveCopiesMap.size() + 2 ;
}
private String getRelativeSourcePath(Resource rootResource, Resource currResource) {
String relSourcePath = currResource.getPath().replaceFirst(rootResource.getPath(), "");
if (relSourcePath.startsWith("/")) {
relSourcePath = relSourcePath.replaceFirst("/", "");
}
return relSourcePath;
}
private Map getFilteredNames(RangeIterator rootRelations) {
Map names = new TreeMap();
String previousPath = null;
String[] prefix = null;
String prefixStr = "";
while (rootRelations.hasNext()) {
LiveRelationship relation = (LiveRelationship) rootRelations.next();
String lcPath = relation.getLiveCopy().getPath();
if(prefix == null) {
//first time: initialize prefix
prefix = Text.explode(lcPath, '/');
} else {
//prefixStr will always contain the last computed prefix
prefixStr = "";
String[] pathExploded = Text.explode(lcPath, '/');
//find common root with prefix
int i = 0;
for(; i< prefix.length && i < pathExploded.length; i++) {
if(prefix[i] == null || !pathExploded[i].equals(prefix[i])) {
break;
}
prefixStr += "/" + prefix[i];
}
//previous loop must find first exclusion index; remove from suffix everything after i
for(; i < prefix.length; i++) {
prefix[i] = null;
}
}
names.put(relation.getTargetPath(),lcPath);
}
//names should contain non filter pathes --> remove prefix from pathes
for (String key : names.keySet()) {
String path = names.get(key);
path = path.substring(prefixStr.length() + 1);
if(path.startsWith("content/")) {
path = path.substring(8);
}
names.put(key, path);
}
return names;
}
private String getStatus(LiveRelationshipManager relationMgr, Resource source, String targetFilter) throws Exception {
RangeIterator pageRelations = relationMgr.getLiveRelationships(source, targetFilter, null);
if (pageRelations == null) {
return MSM_STATUS_TARGET_DOES_NOT_EXIST;
}
while (pageRelations.hasNext()) {
LiveRelationship currRelationship = (LiveRelationship) pageRelations.next();
if (currRelationship.getTargetPath().equals(targetFilter)) {
LiveStatus status = currRelationship.getStatus();
Map advanceStatus = status.getAdvancedStatus();
if (!status.isCancelled()) {
if (status.isTargetExisting() && status.isSourceExisting() && !getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_TARGET_MANUALLY_CREATED)) {
if (getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_SOURCE_MODIFIED)) {
return MSM_STATUS_SOURCE_MODIFIED;
} else {
if ( getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_TARGET_MODIFIED)) {
return MSM_STATUS_TARGET_MODIFIED;
} else {
return MSM_STATUS_STNCHRONIZED;
}
}
} else {
if (status.isSourceExisting()) {
if (getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_TARGET_MANUALLY_CREATED)) {
return MSM_STATUS_NEW;
} else {
return MSM_STATUS_TARGET_DOES_NOT_EXIST;
}
} else if (getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_SOURCE_DELETED)) {
return MSM_STATUS_CANCELLED;
}
}
} else {
if ( getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_SOURCE_EXISTING) || !getAdvanceStatusValue(advanceStatus, MSMNameConstants.PARAM_IS_SOURCE_DELETED)) {
return MSM_STATUS_CANCELLED;
}
}
}
}
return MSM_STATUS_TARGET_DOES_NOT_EXIST;
}
private boolean getAdvanceStatusValue(Map advanceStatus, String param) {
if (advanceStatus.containsKey(param) && advanceStatus.get(param)) {
return true;
}
return false;
}
private static class StatusDetails {
private String iconName;
private String iconClass;
private String statusMessage;
private StatusDetails (String iconName, String iconClass, String statusMessage) {
this.iconClass = iconClass;
this.iconName = iconName;
this.statusMessage = statusMessage;
}
public String getIconName() {
return iconName;
}
public String getIconClass() {
return iconClass;
}
public String getStatusMessage() {
return statusMessage;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy