
com.day.cq.dam.commons.util.DamLanguageUtil Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2015 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.
**************************************************************************/
/**
* AdobePatentID="P6809-US"
*/
package com.day.cq.dam.commons.util;
import com.adobe.cq.dam.cfm.FragmentData;
import com.adobe.cq.dam.cfm.SemanticDataType;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.AccessDeniedException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Workspace;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockManager;
import javax.jcr.lock.LockException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import com.adobe.cq.dam.cfm.ContentElement;
import com.adobe.cq.dam.cfm.ContentFragment;
import com.adobe.cq.dam.cfm.ContentFragmentException;
import com.adobe.cq.dam.cfm.ContentVariation;
import com.adobe.granite.asset.api.AssetRelation;
import com.adobe.granite.confmgr.Conf;
import com.adobe.granite.security.authorization.AuthorizationService;
import com.adobe.granite.translation.api.TranslationConstants;
import com.adobe.granite.translation.api.TranslationException;
import com.adobe.granite.translation.core.MachineTranslationCloudConfig;
import com.day.cq.dam.api.Rendition;
import com.day.cq.wcm.api.WCMException;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.commons.JcrUtils;
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.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.resource.api.JcrResourceConstants;
import org.apache.sling.resource.collection.ResourceCollection;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.commons.Language;
import com.day.cq.commons.LanguageUtil;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.PageManagerFactory;
import com.day.text.Text;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import static com.day.cq.commons.jcr.JcrConstants.JCR_CONTENT;
import static com.day.cq.commons.jcr.JcrConstants.JCR_LASTMODIFIED;
import static com.day.cq.commons.jcr.JcrConstants.JCR_TITLE;
import static com.day.cq.commons.jcr.JcrConstants.NT_FOLDER;
import static com.day.cq.commons.jcr.JcrConstants.JCR_UUID;
/**
* This class provides utility method for Language Copy used by sites
*/
public class DamLanguageUtil {
private static final Logger log = LoggerFactory.getLogger(DamLanguageUtil.class);
private static final String ATTRIBUTE_DESTINATION_LANGUAGE_COPY_PATH = "dam:destinationLanguageCopy";
private static final String ATTRIBUTE_EXTRACT_METADATA = "dam:extractMetadata";
private static final String ATTRIBUTE_SMART_ASSET_UPDATE_SOURCE = "dam:smartAssetUpdateSource";
private static final String ATTRIBUTE_SMART_ASSET_UPDATE_REQUIRED = "dam:smartAssetUpdateRequired";
private static final String ATTRIBUTE_CLOUD_CONFIG_PROPERTY = "cq:cloudserviceconfigs";
private static final String ATTRIBUTE_CA_CONFIG_PROPERTY = "cq:conf";
private static final String ATTRIBUTE_CQ_TRANSLATION_SOURCE_PATH = "cq:translationSourcePath";
private static final String CACONFIG_ROOT = "/conf";
private static final String CACONFIG_GLOBAL = CACONFIG_ROOT + "/global";
private static final String CACONFIG_TRANSLATIONCFG_PATH = "cloudconfigs/translation/translationcfg";
private static final String DEFAULT_LANGUAGES_HOME = "wcm/core/resources/languages";
private static final String ASSET_PERFORMANCE_NODE_RELATIVE_PATH = "/" + JCR_CONTENT + "/" + "performance";
private static final String ASSET_USAGE_NODE_RELATIVE_PATH = "/" + JCR_CONTENT + "/" + DamConstants.USAGES_FOLDER;
private static final String ASSET_VERSION_MESSAGE = "Created by Asset Update Translation";
private static final String ASSOCIATED_CONTENT_RELATIVE_PATH = JcrConstants.JCR_CONTENT + "/associated";
private static final String ASSOCIATED_CONTENT_CHILD = "associated";
private static final String CONTENT_FRAGMENT = "contentFragment";
private static final String ATTRIBUTE_ASSET_DERIVED_RELATION = "derived";
private static final String ATTRIBUTE_ASSET_OTHERS_RELATION = "others";
private static final String MIME_TYPE_HTML = "text/html";
private static final int MAX_DIFF_MILLISECOND_CHANGED = 2000; // max diff allowed in difference is 2sec
private static final String RESOURCE_TYPE_CFM_CONTENT_REFERENCE = "dam/cfm/models/editor/components/contentreference";
private static final String ATTRIBUTE_CQ_TRANSLATION_CREATED= "cq:isTransCreated";
private static final String ATTRIBUTE_CQ_TRANSLATION_STATUS = "cq:translationStatus";
public static final String ATTRIBUTE_ASSET_LINKS_RELATION = "links";
public static final String ATTRIBUTE_ASSET_SOURCE_RELATION = "sources";
public static final String ATTRIBUTE_ASSET_UPDATE_REQUIRED = "dam:assetUpdateRequired";
public static final String ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY = "dam:collectionSourceLanguageCopy";
public static final String CQ_LASTMODIFIED = "cq:lastModified";
public static final String ATTRIBUTE_CQ_TRANSLATION_LAST_UPDATE = "cq:lastTranslationUpdate";
private static final String LIBS_RULES_FILE_PATH = "/libs/settings/translation/rules/translation_rules.xml";
private static final String APPS_RULES_FILE_PATH = "/apps/settings/translation/rules/translation_rules.xml";
private static final String LEGACY_ETC_RULES_FILE_PATH = "/etc/workflow/models/translation/translation_rules.xml";
private static final String CONF_RULES_FILE_PATH = "/conf/global/settings/translation/rules/translation_rules.xml";
private static final String[] RULE_FILES_PRIORITY_ARRAY = {CONF_RULES_FILE_PATH, APPS_RULES_FILE_PATH,
LEGACY_ETC_RULES_FILE_PATH, LIBS_RULES_FILE_PATH};
private static final String ELEMENT_CONTENT_FILTER_NODE = "contentFilterNode";
private static final String ATTRIBUTE_CONTENT_FILTER_VALUE = "value";
private static final String ATTRIBUTE_CONTENT_CREATE_LANG_COPY = "createLanguageCopy";
private static final String CQ_TAG_NAME = "cq:tags";
private static final String METADATA = "metadata";
private static final String CHANGE_BY_TRANSLATION_WORKFLOW = "changeByTranslationWorkflow";
private static final String CQ_TRANSLATION_SOURCE_JCR_UUID = "cq:translationSourceUUID";
private static final String CQ_LANGUAGE_ROOT = "cq:languageRoot";
/**
* Category for translation while creating and updating language copies. This is a list of all possible language
* copy locations.
*/
private enum TranslationCategory {
/**
* Language copy translation is not required.
*/
NONE,
/**
* Destination Language copy needs to be created or updated.
*/
DESTINATION,
/**
* Temporary Language copies are required.
*/
TEMPORARY
}
/**
* possible states of content.
*/
private enum ContentState {
/**
* content is updated.
*/
IS_UPDATE_STATE,
/**
* content is translated.
*/
IS_TRANSLATED,
/**
* content is for creation.
*/
IS_CREATE_STATE,
/**
* Unknown stage of Content.
*/
IS_UNKNOWN
}
/**
* This method returns true if language copy of an asset exists, for the
* asked locale
*
* @param assetPath The path of an asset for which language copy is asked
* @param languageCode Language for which language copy is asked
* @param resolver ResourceResolver
* @return
*/
public static boolean hasLanguageCopy(final String assetPath,
final String languageCode, final ResourceResolver resolver) {
Asset asset = findLanguageCopy(assetPath, languageCode, resolver);
if (asset != null) return true;
return false;
}
/**
* This method returns the Language copy asset if language copy exists, for
* the asked locale
*
* @param assetPath The path of an asset for which language copy is asked
* @param languageCode Language for which language copy is asked
* @param resolver ResourceResolver
* @return
*/
public static Asset getLanguageCopy(final String assetPath,
final String languageCode, final ResourceResolver resolver) {
return findLanguageCopy(assetPath, languageCode, resolver);
}
/**
* This method creates language copy of an asset/folder
* Adds Smart translation properties when language copy is present
*
* @param resourceResolver
* @param pageManagerFactory
* @param sourcePath - source for creating language copy
* @param targetLanguageCodes - array of language codes
* @return
*/
public static List createLanguageCopy(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final String[] targetLanguageCodes) {
Session session = resourceResolver.adaptTo(Session.class);
PageManager pageManager = pageManagerFactory.getPageManager(resourceResolver);
Resource sourceResource = resourceResolver.getResource(sourcePath);
List createdCopies = new ArrayList();
String contentPath = "";
if (targetLanguageCodes == null || targetLanguageCodes.length == 0 || targetLanguageCodes[0].trim().length() == 0) {
log.error("Failed to load destination language from payload.");
return createdCopies;
}
String root = LanguageUtil.getLanguageRoot(sourcePath);
String parentOfRoot = null;
boolean createNewLanguageRoot = false;
Node sourceLanguageRootNode = null;
Node sourceLRContentNode = null;
if (root == null) {
log.debug("Language root does not exist for asset at path: {} and would be created. ", sourcePath);
//CQ-61450 User creates a language copy of a page from sites and language root for the asset (referenced in site) does not exist
if (Text.getRelativeParent(sourcePath, 1).equals(DamConstants.MOUNTPOINT_ASSETS)) {
//Asset is directly under DamConstants.MOUNTPOINT_ASSETS
parentOfRoot = DamConstants.MOUNTPOINT_ASSETS;
root = DamConstants.MOUNTPOINT_ASSETS;
} else if (sourcePath.startsWith(DamConstants.MOUNTPOINT_ASSETS + "/")) {
//Asset follows structure DamConstants.MOUNTPOINT_ASSETS//
int parentOfRootPathLength = sourcePath.indexOf('/', DamConstants.MOUNTPOINT_ASSETS.length() + 1);
int oldRootPathLength = sourcePath.indexOf('/', parentOfRootPathLength);
if (parentOfRootPathLength < 0 || sourcePath.length() <= parentOfRootPathLength) {
return createdCopies;
}
parentOfRoot = sourcePath.substring(0, parentOfRootPathLength);
if (oldRootPathLength > 0 && sourcePath.length() > oldRootPathLength) {
root = sourcePath.substring(0, oldRootPathLength);
}
}
createNewLanguageRoot = true;
log.info("Parent of New Language root at path {} added for asset at path {}", parentOfRoot, sourcePath);
if (parentOfRoot != null) {
contentPath = sourcePath.replaceFirst(parentOfRoot, "");
} else {
parentOfRoot = "";
}
} else {
contentPath = sourcePath.replaceFirst(root, "");
parentOfRoot = Text.getRelativeParent(root, 1);
}
//for every indivisual asset, for every target langauge code
for (int i = 0; i < targetLanguageCodes.length; i++) {
String targetPath = "";
String languageRootPath = "";
String strDestinationLanguage = getDestinationLanguageWithAllowedDelimiters(parentOfRoot,
targetLanguageCodes[i], resourceResolver);
languageRootPath = getDestinationLanguageRoot(parentOfRoot, strDestinationLanguage, resourceResolver);
targetPath = languageRootPath + contentPath;
String transCreatedPath = "" ;
String pathToCheck = "";
try {
if (contentPath.trim().length() > 0) {
String pathToCreate = Text.getRelativeParent(
targetPath, 1);
pathToCheck = pathToCreate.replaceFirst(DamConstants.MOUNTPOINT_ASSETS, "") + "/";
transCreatedPath = getTransCreatedPath(pathToCheck, session);
String nodeType = "sling:Folder";
sourceLanguageRootNode = session.getNode(root);
sourceLRContentNode = sourceLanguageRootNode.getNode(JcrConstants.JCR_CONTENT);
if (sourceLanguageRootNode.isNodeType(
"sling:OrderedFolder")) {
nodeType = "sling:OrderedFolder";
}
JcrUtil.createPath(pathToCreate, nodeType,
nodeType, session, false);
}
if (!session.nodeExists(targetPath)) {
Resource destinationResource = pageManager.copy(sourceResource, targetPath, null, false,
false, false);
// Remove Derived, Others Relations from this resource, if any. Ensures that if this resource,
// is a source Asset then the derived, others relations don't point to old language copies
if (destinationResource != null) {
com.adobe.granite.asset.api.Asset destinationGraniteAsset = destinationResource.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (destinationGraniteAsset != null) {
removeAssetRelation(destinationGraniteAsset, ATTRIBUTE_ASSET_DERIVED_RELATION);
removeAssetRelation(destinationGraniteAsset, ATTRIBUTE_ASSET_OTHERS_RELATION);
}
associateSourceJcrUuidToAssetLanguageCopyAndSetLanguageRoot(destinationResource, sourceResource, session, strDestinationLanguage);
addTranslationSourcePath(destinationResource, sourceResource.getPath());
setLastTranslationUpdate(destinationResource);
setIsTranslationCreated(destinationResource);
deleteInsightData(destinationResource.getPath(), resourceResolver);
}
//changing the title and set the Cloud Configs (CQ-61476) on the language root folder
Node targetNode = session.getNode(languageRootPath);
if (targetNode != null) {
if (!targetNode.hasNode(JcrConstants.JCR_CONTENT)) {
targetNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node content = targetNode.getNode(JcrConstants.JCR_CONTENT);
if (!content.hasProperty(JcrConstants.JCR_TITLE)) {
String displayLanguage = getLanguageDisplayName(resourceResolver, strDestinationLanguage);
content.setProperty(JcrConstants.JCR_TITLE, displayLanguage);
}
if (sourceLRContentNode != null) {
// Set the cq:conf property on target LR folder if the source language root folder has and target doesn't have it
if (!content.hasProperty(ATTRIBUTE_CA_CONFIG_PROPERTY) &&
sourceLRContentNode.hasProperty(ATTRIBUTE_CA_CONFIG_PROPERTY)) {
content.setProperty(ATTRIBUTE_CA_CONFIG_PROPERTY,
sourceLRContentNode.getProperty(ATTRIBUTE_CA_CONFIG_PROPERTY).getString());
}
// Set the cq:cloudserviceconfigs property on target LR folder if the source language root folder has and target doesn't have it
if (!content.hasProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY) &&
sourceLRContentNode.hasProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY)) {
content.setProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY,
sourceLRContentNode.getProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY).getValues());
}
}
//set JCR_TITLE and Cloud Configs (CQ-61476) for all folders in the created contentPath and language root
String tempAddTitlePath = contentPath.substring(0, contentPath.lastIndexOf('/'));
while (tempAddTitlePath.length() > 0) {
Node tempNode = session.getNode(languageRootPath + tempAddTitlePath);
if (tempNode != null) {
if (!tempNode.hasNode(JcrConstants.JCR_CONTENT)) {
tempNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node tempNodeContent = tempNode.getNode(JcrConstants.JCR_CONTENT);
String sourceNodeForTitle = null;
if (createNewLanguageRoot) {
sourceNodeForTitle = parentOfRoot + tempAddTitlePath;
} else {
sourceNodeForTitle = root + tempAddTitlePath;
}
if (!tempNodeContent.hasProperty(JcrConstants.JCR_TITLE)) {
String tempNodeTitle = UIHelper.getTitle(resourceResolver.getResource(sourceNodeForTitle));
tempNodeContent.setProperty(JcrConstants.JCR_TITLE, tempNodeTitle);
Node sourceNode = session.getNode(sourceNodeForTitle);
if (sourceNode != null) {
Node sourceContentNode = sourceNode.getNode(JcrConstants.JCR_CONTENT);
if (sourceContentNode != null) {
// Set the cq:conf property on this folder if relative folder in source path has and target doesn't have it
if (!tempNodeContent.hasProperty(ATTRIBUTE_CA_CONFIG_PROPERTY) &&
sourceContentNode.hasProperty(ATTRIBUTE_CA_CONFIG_PROPERTY)) {
tempNodeContent.setProperty(ATTRIBUTE_CA_CONFIG_PROPERTY,
sourceContentNode.getProperty(ATTRIBUTE_CA_CONFIG_PROPERTY).getString());
}
// Set the cq:cloudserviceconfigs property on this folder if relative folder in source path has and target doesn't have it
if (!tempNodeContent.hasProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY) &&
sourceContentNode.hasProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY)) {
tempNodeContent.setProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY,
sourceContentNode.getProperty(ATTRIBUTE_CLOUD_CONFIG_PROPERTY).getValues());
}
}
}
}
tempAddTitlePath = tempAddTitlePath.substring(0, tempAddTitlePath.lastIndexOf('/'));
}
}
//set IsTransCreated on Translation Created Folders
String pathAlreadyPresent = DamConstants.MOUNTPOINT_ASSETS + pathToCheck.substring(0, pathToCheck.indexOf(transCreatedPath));
setTransCreatedFlagToPathResource(transCreatedPath, pathAlreadyPresent, resourceResolver);
}
} else {
log.info(
"Could not create language copy for assets at path: " + targetPath +
", resource already exists. Updating language copy.");
Asset sourceAsset =null, targetAsset = null;
if (resourceResolver.getResource(sourcePath) != null) {
sourceAsset = resourceResolver.getResource(sourcePath).adaptTo(Asset.class);
}
if (resourceResolver.getResource(targetPath) != null) {
targetAsset = resourceResolver.getResource(targetPath).adaptTo(Asset.class);
}
if (sourceAsset != null && targetAsset != null) {
ContentState contentState = getContentStateForSmartTranslation(sourceAsset, targetAsset, resourceResolver);
if (contentState != ContentState.IS_TRANSLATED && contentState != ContentState.IS_UNKNOWN) {
addSmartAssetUpdateSource(targetAsset, sourcePath);
if (contentState == ContentState.IS_UPDATE_STATE) {
addSmartAssetUpdateProperty(targetAsset, true);
}
} else {
addSmartAssetUpdateProperty(targetAsset, false);
}
}
}
if (session.hasPendingChanges()) {
session.save();
}
createdCopies.add(targetPath);
} catch (Exception e) {
// if failed before saving the sesion then refresh it (skip the current asset)
if (session != null && session.isLive()) {
try {
session.refresh(false); //keepChanges = false (discard all changes to skip the current asset)
} catch (RepositoryException re) {
log.error("error while refreshing the session: ", re);
}
}
log.error( "error while creating language copy for assets at path: " + targetPath + "{}", e);
}
}
return createdCopies;
}
private static void associateSourceJcrUuidToAssetLanguageCopyAndSetLanguageRoot(Resource destinationResource, Resource srcResource, Session session, String strDestinationLanguage) throws RepositoryException {
if(destinationResource != null && srcResource != null){
Node destinationNode = destinationResource.adaptTo(Node.class);
Node srcNode = srcResource.adaptTo(Node.class);
if (srcNode != null && destinationNode != null) {
if (!srcNode.hasProperty(JCR_UUID)) {
LockProperties lockProperties = new LockProperties.PropertyBuilder().build();
try {
// Lock the node to avoid concurrent modification on source node
addMixinTypeInNodeWithLock(srcNode, JcrConstants.MIX_REFERENCEABLE, lockProperties);
} catch (AccessDeniedException e) {
String errorMessage = String.format("Taking lock on node [%s] failed. Access denied to lock node", srcNode.getPath());
log.error(errorMessage, e);
// To do. Add notification to user when Sync feature is enabled. https://jira.corp.adobe.com/browse/CQ-4357718
} catch (LockException e) {
String errorMessage = String.format("Taking lock on node [%s] failed. Node is already locked by another session",
srcNode.getPath());
log.error(errorMessage, e);
// To do. Add notification to user when Sync feature is enabled. https://jira.corp.adobe.com/browse/CQ-4357718
} catch (TranslationException e) {
String errorMessage = String.format("Taking lock on node [%s] failed.", srcNode.getPath());
log.error(errorMessage, e);
// To do. Add notification to user when Sync feature is enabled. https://jira.corp.adobe.com/browse/CQ-4357718
}
}
if (srcNode.hasProperty(JCR_UUID)) {
String uuid = srcNode.getProperty(JCR_UUID).getValue().toString();
if (!StringUtils.isEmpty(uuid)) {
if (destinationNode.hasNode(JCR_CONTENT)) {
Node jcrContent = destinationNode.getNode(JCR_CONTENT);
jcrContent.setProperty(CQ_TRANSLATION_SOURCE_JCR_UUID, uuid, PropertyType.WEAKREFERENCE);
log.debug("cq:TranslationSourceUUID set for resource {} from source {}", destinationResource.getPath(), srcResource.getPath());
jcrContent.setProperty(CQ_LANGUAGE_ROOT, strDestinationLanguage);
log.debug( CQ_LANGUAGE_ROOT + " set for resource {} to value {}", destinationResource.getPath(), strDestinationLanguage);
} else {
log.error("Error while Associating Source JCR UUID to Asset Language copy, destination's jcr:content node doesn't exist for {}", destinationResource.getPath());
}
} else {
log.error("Error while Associating Source JCR UUID to Asset Language copy, Source JCR UUID for Node is empty: {}", srcNode.getPath());
}
} else {
log.error("Error while Associating Source JCR UUID to Asset Language copy, source node: {} uuid doesn't exist", srcResource.getPath());
}
} else {
log.error("Error while Associating Source JCR UUID to Asset Language copy, source node : {} or destination node is null", srcResource.getPath(), destinationNode.getPath());
}
}
}
/**
* This method is used to add mixin type to a node after locking it and unlocing it afterwards.
* @param node
* @param mixinType
* @param lockProperties
* @throws RepositoryException
* @throws TranslationException
*/
private static void addMixinTypeInNodeWithLock(Node node, String mixinType, LockProperties lockProperties)
throws RepositoryException, TranslationException {
Session session = node.getSession();
Lock lock;
try {
lock = LockUtil.lockNode(node, lockProperties);
} catch (LockException | AccessDeniedException | TranslationException e) {
throw e;
}
if (lock != null) {
if (node.canAddMixin(mixinType)) {
node.addMixin(mixinType);
session.save();
}
// Unlock the node
try {
if (LockUtil.canUnlock(node)) {
LockUtil.unlockNode(node);
} else {
String errorMessage = String.format("User %s does not have permission to unlock resource %s." +
" This node is locked by user %s. Please contact the administrator.", session.getUserID(), node.getPath(),
lock.getLockOwner());
log.error(errorMessage);
throw new AccessDeniedException(errorMessage);
}
} catch (LockException | AccessDeniedException | TranslationException e) {
log.error("Error while unlocking the node", e);
}
}
}
private static void addTranslationSourcePath(Resource destinationResource, String translationSourcePath) throws
RepositoryException {
if (destinationResource != null) {
Node destNode = destinationResource.adaptTo(Node.class);
if (destNode != null) {
Node contentNode = destNode.getNode(JCR_CONTENT);
if (contentNode != null) {
contentNode.setProperty(ATTRIBUTE_CQ_TRANSLATION_SOURCE_PATH, translationSourcePath);
}
} else {
log.warn("Resource not able to adaptTo Node object while adding translation source path:" + destinationResource.getPath());
}
}
}
private static Asset findLanguageCopy(final String assetPath,
final String languageCode, final ResourceResolver resolver) {
Resource assetResource = resolver.getResource(assetPath);
if (assetResource == null || assetResource.adaptTo(Asset.class) == null) {
return null;
}
Asset asset = null;
String languageRootPath = LanguageUtil.getLanguageRoot(assetPath);
if(languageRootPath == null){
return null;
}
String contentPath = assetPath.replaceFirst(languageRootPath, "");
String languageRootParentPath = Text.getRelativeParent(
languageRootPath, 1);
String destinationLanguageRootPath = getDestinationLanguageRoot(languageRootParentPath , languageCode,
resolver);
String assetPathLC = destinationLanguageRootPath + contentPath;
Resource assetResourceLC = resolver.getResource(assetPathLC);
if (assetResourceLC != null) {
asset = assetResourceLC.adaptTo(Asset.class);
}
return asset;
}
/**
* Returns the language root for the given asset path by only analyzing the
* path names starting at the root. For this implementation, language root
* for dam was suffix of folder name joined by "-" ex. geometrixx-en.
*
* @param path path
* @return the language root or null
if not found
*
* @deprecated since 6.2, use {@link com.day.cq.commons.LanguageUtil} instead
*/
@Deprecated
public static String getLanguageRoot(String path) {
throw new UnsupportedOperationException("This API has been deprecated.Please use com.day.cq.commons.LanguageUtil instead.");
}
/**
* Returns the language for the given asset path by only analyzing the
* path names starting at the root. For this implementation, language
* root for dam was suffix of folder name joined by "-" ex. geometrixx-en.
*
* @param path path
* @return the language or null
if not found
*
* @deprecated since 6.2, use {@link com.day.cq.commons.LanguageUtil} instead
*/
@Deprecated
public static Language getLanguage(String path) {
throw new UnsupportedOperationException("This API has been deprecated.Please use com.day.cq.commons.LanguageUtil instead.");
}
/**
* Modified version of com.day.cq.wcm.core.impl.LanguageManagerImpl for Resources
*
* Returns a collection of language root pages for the given asset. Note that
* only the path names are respected for the determination of the language.
*
* @param resolver resource resolver
* @param path path of the current page
* @return collection of language root paths
*/
public static Collection getLanguageRoots(ResourceResolver resolver, String path) {
Iterator resources = getLanguageRootSiblings(resolver, path);
if (resources == null) {
return Collections.emptySet();
}
List roots = new ArrayList();
while(resources.hasNext()) {
Resource res = resources.next();
Locale locale = getLocaleFromResource(res);
if (locale != null) {
roots.add(res);
}
}
Resource currentResource = resolver.getResource(path);
if (currentResource != null) {
Resource langRoot = getLanguageRootResource(currentResource);
if (null != langRoot) {
Resource langRootParent = langRoot.getParent();
boolean additionalLanguageRootsFound = false;
//go one level down
Iterator iter = langRootParent.listChildren();
while (iter.hasNext()) {
Resource sibling = iter.next();
Locale locale = getLocaleFromResource(sibling);
if (locale == null) {
additionalLanguageRootsFound = addLanguageRootsFromChildren(roots,
additionalLanguageRootsFound, sibling);
}
}
if (additionalLanguageRootsFound) {
//found roots one level down, no need to go up. Therefore, return
return roots;
}
//one level up
//find language roots which are not language countries
Resource langRootGrandParent = langRootParent.getParent();
ArrayList nonLangRootUncles = new ArrayList();
if (langRootGrandParent != null) {
Iterator langRootUncles = langRootGrandParent.listChildren();
while (langRootUncles.hasNext()) {
Resource langRootUncle = langRootUncles.next();
if (langRootUncle.getName().equals(langRootParent.getName())) { //node comparison not working :(
//already added
continue;
}
Locale gcLocale = getLocaleFromResource(langRootUncle);
//todo check that this is not a country node
if (gcLocale != null && !isCountryNode(langRootUncle)) {
roots.add(langRootUncle);
additionalLanguageRootsFound = true;
} else {
nonLangRootUncles.add(langRootUncle);
}
}
}
if (!additionalLanguageRootsFound) {
//didn't found roots one level up, no need to go down on nonLangRootUncles. Therefore, return
return roots;
}
for (Resource nonLangRootUncle : nonLangRootUncles) {
additionalLanguageRootsFound = addLanguageRootsFromChildren(roots,
additionalLanguageRootsFound, nonLangRootUncle);
}
}
}
return roots;
}
private static boolean addLanguageRootsFromChildren(List roots, boolean additionalLanguageRootsFound,
Resource resource) {
Iterator children = resource.listChildren();
while (children.hasNext()) {
Resource child = children.next();
Locale childLocale = getLocaleFromResource(child);
if (childLocale != null) {
roots.add(child);
additionalLanguageRootsFound = true;
}
}
return additionalLanguageRootsFound;
}
private static Iterator getLanguageRootSiblings(ResourceResolver resolver, @Nonnull String path) {
String root = LanguageUtil.getLanguageRoot(path);
if (root == null) {
return null;
}
String parent = Text.getRelativeParent(root, 1);
Resource parentResource = resolver.getResource(parent);
if (parentResource == null) {
return null;
}
return resolver.listChildren(parentResource);
}
private static Resource getLanguageRootResource(@Nonnull Resource res) {
String rootPath = LanguageUtil.getLanguageRoot(res.getPath());
if (rootPath == null) {
return null;
}
return res.getResourceResolver().getResource(rootPath);
}
/**
* This method creates update language copy of an asset/folder
*
* @param resourceResolver
* @param pageManagerFactory
* @param sourcePath - source for creating language copy
* @param targetLanguageCode - destination language code
* @param prefixPath - Root path where language copies are created
* @return
*/
public static String createUpdateLanguageCopy(final ResourceResolver resourceResolver, final PageManagerFactory pageManagerFactory, final String sourcePath,
final String targetLanguageCode, String prefixPath) {
Session session = resourceResolver.adaptTo(Session.class);
PageManager pageManager = pageManagerFactory.getPageManager(resourceResolver);
Resource sourceResource = resourceResolver.getResource(sourcePath);
String createdCopy = "";
String contentPath = "";
if (targetLanguageCode == null || targetLanguageCode.trim().length() == 0) {
log.error("Failed to load destination language from payload.");
return null;
}
String root = LanguageUtil.getLanguageRoot(sourcePath);
String parentOfRoot = null;
boolean createNewLanguageRoot = false;
if (root == null) {
log.debug("Language root does not exist for asset at path: {} and would be created. ", sourcePath);
//CQ-61450 User creates a language copy of a page from sites and language root for the asset (referenced in site) does not exist
if (Text.getRelativeParent(sourcePath, 1).equals(DamConstants.MOUNTPOINT_ASSETS)) {
//Asset is directly under DamConstants.MOUNTPOINT_ASSETS
parentOfRoot = DamConstants.MOUNTPOINT_ASSETS;
root = DamConstants.MOUNTPOINT_ASSETS;
} else if (sourcePath.startsWith(DamConstants.MOUNTPOINT_ASSETS + "/")) {
//Asset follows structure DamConstants.MOUNTPOINT_ASSETS//
int parentOfRootPathLength = sourcePath.indexOf('/', DamConstants.MOUNTPOINT_ASSETS.length() + 1);
int oldRootPathLength = sourcePath.indexOf('/', parentOfRootPathLength);
if (parentOfRootPathLength < 0 || sourcePath.length() <= parentOfRootPathLength) {
return createdCopy;
}
parentOfRoot = sourcePath.substring(0, parentOfRootPathLength);
if (oldRootPathLength > 0 && sourcePath.length() > oldRootPathLength) {
root = sourcePath.substring(0, oldRootPathLength);
}
}
createNewLanguageRoot = true;
log.info("Parent of New Language root at path {} added for asset at path {}", parentOfRoot, sourcePath);
if (parentOfRoot != null) {
contentPath = sourcePath.replaceFirst(parentOfRoot, "");
} else {
parentOfRoot = "";
}
} else {
contentPath = sourcePath.replaceFirst(root, "");
parentOfRoot = Text.getRelativeParent(root, 1);
}
String targetPath = "";
String languageRootPath = "";
String strDestinationLanguage = getDestinationLanguageWithAllowedDelimiters(prefixPath + parentOfRoot,
targetLanguageCode, resourceResolver);
languageRootPath = prefixPath + getDestinationLanguageRoot(parentOfRoot, strDestinationLanguage,
resourceResolver);
targetPath = languageRootPath + contentPath;
String destAssetPath = getDestinationLanguageRoot(parentOfRoot, strDestinationLanguage, resourceResolver) + contentPath;;
try {
// if (contentPath.trim().length() > 0) {
String pathToCreate = Text.getRelativeParent(
targetPath, 1);
String nodeType = "sling:Folder";
if (session.getNode(root).isNodeType(
"sling:OrderedFolder")) {
nodeType = "sling:OrderedFolder";
}
JcrUtil.createPath(pathToCreate, nodeType,
nodeType, session, false);
// }
if (null == resourceResolver.getResource(targetPath)) {
if (DamUtil.isAsset(sourceResource)) {
Resource destinationResource = pageManager.copy(sourceResource, targetPath, null, false, true, false);
// Remove Derived, Others Relations from this resource, if any. Ensures that if this resource,
// is a source Asset then the derived, others relations don't point to old language copies
if (destinationResource != null) {
com.adobe.granite.asset.api.Asset destinationGraniteAsset = destinationResource.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (destinationGraniteAsset != null) {
removeAssetRelation(destinationGraniteAsset, ATTRIBUTE_ASSET_DERIVED_RELATION);
removeAssetRelation(destinationGraniteAsset, ATTRIBUTE_ASSET_OTHERS_RELATION);
}
Resource destAssetResource = resourceResolver.getResource(destAssetPath);
associateSourceJcrUuidToAssetLanguageCopyAndSetLanguageRoot(destAssetResource, sourceResource, session, strDestinationLanguage);
addTranslationSourcePath(destinationResource, sourceResource.getPath());
setLastTranslationUpdate(destinationResource);
setIsTranslationCreated(destinationResource);
deleteInsightData(destinationResource.getPath(), resourceResolver);
removeAllRenditionsInsideResource(destinationResource);
String destinationForTemporaryAsset = parentOfRoot + "/" + strDestinationLanguage + contentPath;
setDestinationLanguageCopyPath(destinationResource, destinationForTemporaryAsset);
createdCopy = destinationResource.getPath();
}
}
//changing the title of the folder
Node targetNode = session.getNode(languageRootPath);
if (targetNode != null) {
if (!targetNode.hasNode(JcrConstants.JCR_CONTENT)) {
targetNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node content = targetNode.getNode(JcrConstants.JCR_CONTENT);
if (!content.hasProperty(JcrConstants.JCR_TITLE)) {
String displayLanguage = getLanguageDisplayName(resourceResolver, strDestinationLanguage);
content.setProperty(JcrConstants.JCR_TITLE, displayLanguage);
}
//set JCR_TITLE for all folders in the created contentPath and language root
String tempAddTitlePath = contentPath.substring(0, contentPath.lastIndexOf('/'));
while (tempAddTitlePath.length() > 0) {
Node tempNode = session.getNode(languageRootPath + tempAddTitlePath);
if (tempNode != null) {
if (!tempNode.hasNode(JcrConstants.JCR_CONTENT)) {
tempNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node tempNodeContent = tempNode.getNode(JcrConstants.JCR_CONTENT);
String sourceNodeForTitle = null;
if (createNewLanguageRoot) {
sourceNodeForTitle = parentOfRoot + tempAddTitlePath;
} else {
sourceNodeForTitle = root + tempAddTitlePath;
}
if (!tempNodeContent.hasProperty(JcrConstants.JCR_TITLE)) {
String tempNodeTitle = UIHelper.getTitle(resourceResolver.
getResource(sourceNodeForTitle));
tempNodeContent.setProperty(JcrConstants.JCR_TITLE, tempNodeTitle);
}
tempAddTitlePath = tempAddTitlePath.substring(0, tempAddTitlePath.lastIndexOf('/'));
}
}
}
} else {
createdCopy = targetPath;
}
if (session.hasPendingChanges()) {
session.save();
}
} catch (Exception e) {
// if failed before saving the sesion then refresh it, and ignore all the pending changes for this asset
if (session != null && session.isLive()) {
try {
session.refresh(false); //keepChanges = false (discard all changes to skip the current asset)
}
catch (RepositoryException re) {
log.error("error while refreshing the session: ", re);
}
}
log.error("error while creating language copy for assets at path: " + targetPath + "{}", e);
}
return createdCopy;
}
private static String getDestinationLanguageWithAllowedDelimiters(String contentPath, String strDestinationLanguage,
ResourceResolver resourceResolver) {
String langWithHyphen = strDestinationLanguage.replace("_", "-");
String langWithUnderscore = strDestinationLanguage.replace("-", "_");
boolean langWithHyphenExist = (null != resourceResolver.getResource(contentPath + "/" + langWithHyphen));
boolean langWithUnderscoreExist = (null != resourceResolver.getResource(contentPath + "/" +
langWithUnderscore));
if (langWithHyphenExist && langWithUnderscoreExist) {
return strDestinationLanguage;
} else if (langWithHyphenExist) {
return langWithHyphen;
} else if (langWithUnderscoreExist) {
return langWithUnderscore;
} else {
return strDestinationLanguage;
}
}
private static void deleteInsightData(String resourcePath, ResourceResolver resourceResolver) {
Resource resource = resourceResolver.getResource(resourcePath);
if (resource != null) {
if (DamUtil.isAsset(resource)) {
deleteResource(resourcePath + ASSET_PERFORMANCE_NODE_RELATIVE_PATH, resourceResolver);
deleteResource(resourcePath + ASSET_USAGE_NODE_RELATIVE_PATH, resourceResolver);
} else if (isFolder(resource)) {
Iterator assetIterator = DamUtil.getAssets(resource);
while (assetIterator.hasNext()) {
String assetPath = assetIterator.next().getPath();
deleteResource(assetPath + ASSET_PERFORMANCE_NODE_RELATIVE_PATH, resourceResolver);
deleteResource(assetPath + ASSET_USAGE_NODE_RELATIVE_PATH, resourceResolver);
}
}
}
}
private static void deleteResource(String path, ResourceResolver resourceResolver) {
Resource resource = resourceResolver.getResource(path);
if (resource != null) {
try {
resourceResolver.delete(resource);
} catch (PersistenceException e) {
log.error("Unable to delete resource from {} : {}", resource, e.getMessage());
}
}
}
private static void setDestinationLanguageCopyPath(Resource temporaryResource, String destinationPath)
throws RepositoryException {
Node temporaryNode = temporaryResource.adaptTo(Node.class);
if(temporaryNode != null) {
if (!temporaryNode.hasNode(JcrConstants.JCR_CONTENT)) {
temporaryNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node destinationContentNode = temporaryNode.getNode(JcrConstants.JCR_CONTENT);
destinationContentNode.setProperty(ATTRIBUTE_DESTINATION_LANGUAGE_COPY_PATH, destinationPath);
} else {
log.warn("Resource not able to adaptTo Node object while setting destination language copy path:" + temporaryResource.getPath());
}
}
private static boolean isFolder(Resource resource){
Node n = resource.adaptTo(Node.class);
try {
if (n != null) {
return n.isNodeType(NT_FOLDER);
} else {
log.debug("Resource not able to adaptTo Node object while checking if resource is folder:" + resource.getPath());
}
return false;
} catch (RepositoryException e) {
return false;
}
}
/**
*
* @param sourcePath
* @param destinationPath
* @param userSession
* @param pageManagerFactory
* @param resolverFactory
*
* @deprecated since 6.2, use
* {@link #moveUpdatedAsset(String, String, Session, PageManagerFactory, ResourceResolver)} instead
*/
@Deprecated
public static void moveUpdatedAsset(String sourcePath, String destinationPath, Session userSession,
PageManagerFactory pageManagerFactory, ResourceResolverFactory resolverFactory){
throw new UnsupportedOperationException("This API has been deprecated.Please use moveUpdatedAsset(String, String, Session, PageManagerFactory, "
+ "ResourceResolver) instead.");
}
public static void moveUpdatedAsset(String sourcePath, String destinationPath, Session userSession,
PageManagerFactory pageManagerFactory, ResourceResolver resourceResolver){
Map authInfo = new HashMap();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, userSession);
try {
Resource sourceResource = resourceResolver.getResource(sourcePath);
Resource destinationResource = resourceResolver.getResource(destinationPath);
Asset sourceAsset = DamUtil.resolveToAsset(sourceResource);
if(sourceAsset != null) {
PageManager pageManager = pageManagerFactory.getPageManager(resourceResolver);
if(destinationResource == null){
String pathToCreate = Text.getRelativeParent(
destinationPath, 1);
String nodeType = "sling:Folder";
// if (userSession.getNode(destinationPath).isNodeType(
// "sling:OrderedFolder")) {
// nodeType = "sling:OrderedFolder";
// }
JcrUtil.createPath(pathToCreate, nodeType,
nodeType, userSession, false);
pageManager.copy(sourceResource, destinationPath, null, false,
false, true);
} else {
Asset destinationAsset = DamUtil.resolveToAsset(destinationResource);
if(destinationAsset != null) {
destinationAsset.addRendition(DamConstants.ORIGINAL_FILE, sourceAsset.getOriginal().getBinary(), sourceAsset.getMimeType());
} else {
log.error("Unable to move updated asset : Destination Asset not found");
}
//todo copy metadata
}
userSession.save();
} else {
log.error("Unable to move updated asset : Source Asset not found");
}
} catch (Exception e) {
log.error("Unable to move updated asset {}", e.getMessage());
}
}
/**
* Update the destination asset with all updates done on source asset.
* It will not trigger Asset Processor or Update Asset workflow for the updated asset.
* Caller of the method should trigger Asset Processor or Update Workflow for the
* updated asset to create the renditions of the updated asset.
*
* @param sourcePath Source Path of Asset
* @param destinationPath Destination Path of Asset
* @param userSession Will be used to save the session.
* @param pageManagerFactory Will be use to get pageManager
* @param resourceResolver Will be used to get the resource
*/
public static void replaceUpdatedAsset(String sourcePath, String destinationPath, Session userSession,
PageManagerFactory pageManagerFactory, ResourceResolver resourceResolver){
try {
Resource sourceResource = resourceResolver.getResource(sourcePath);
Resource destinationResource = resourceResolver.getResource(destinationPath);
Asset sourceAsset = sourceResource.adaptTo(Asset.class);
if (sourceAsset!= null && !isContentFragment(sourceAsset)) {
addExtractMetadataPropertyForAsset(sourceAsset, false);
}
//See the discussion on CQ-4235761 and CQ-39476. Copy and create are two separate functionalities and we will
//not trigger update_asset workflow on PageManager.copy(). Hence it needs to be triggered explicitly after this method execution
//to create the renditions of the translated asset.
if(sourceResource != null) {
PageManager pageManager = pageManagerFactory.getPageManager(resourceResolver);
if(destinationResource == null){
String pathToCreate = Text.getRelativeParent(
destinationPath, 1);
String nodeType = "sling:Folder";
JcrUtil.createPath(pathToCreate, nodeType,
nodeType, userSession, false);
pageManager.copy(sourceResource, destinationPath, null, false,
false, true);
} else {
//create version
Asset destinationAsset = resourceResolver.getResource(destinationPath).adaptTo(Asset.class);
String languageRoot = null;
String destJcrUuid = null;
if (destinationAsset != null) {
Node destinationAssetNode = destinationAsset.adaptTo(Node.class);
if (destinationAssetNode != null) {
if (destinationAssetNode.hasNode(JCR_CONTENT)) {
Node destContentNode = destinationAssetNode.getNode(JCR_CONTENT);
if (destContentNode.hasProperty(CQ_TRANSLATION_SOURCE_JCR_UUID)) {
destJcrUuid = destContentNode.getProperty(CQ_TRANSLATION_SOURCE_JCR_UUID).getValue().getString();
}
if (destContentNode.hasProperty(CQ_LANGUAGE_ROOT)) {
languageRoot = destContentNode.getProperty(CQ_LANGUAGE_ROOT).getValue().getString();
}
}
}
destinationAsset.createRevision("", ASSET_VERSION_MESSAGE);
copyInsightData(destinationResource.getPath(), sourceResource.getPath(), resourceResolver,
pageManager);
deleteAllChildren(destinationResource, userSession);
copyAllChildren(sourceResource, destinationResource, pageManager, userSession);
Node updatedDestNode = destinationResource.adaptTo(Node.class);
if (updatedDestNode != null) {
if (updatedDestNode.hasNode(JCR_CONTENT)) {
Node updatedDestNodeJcrContent = updatedDestNode.getNode(JCR_CONTENT);
if (!StringUtils.isEmpty(destJcrUuid)) {
updatedDestNodeJcrContent.setProperty(CQ_TRANSLATION_SOURCE_JCR_UUID, destJcrUuid, PropertyType.WEAKREFERENCE);
}
if (!StringUtils.isEmpty(languageRoot)) {
updatedDestNodeJcrContent.setProperty(CQ_LANGUAGE_ROOT, languageRoot);
}
}
}
} else {
log.error("Unable to move updated asset : Destination is not an Asset");
}
}
userSession.save();
} else {
log.error("Unable to move updated asset : Source Resource not found");
}
} catch (Exception e) {
log.error("Unable to move updated asset {}", e.getMessage());
}
}
private static void copyInsightData(String sourcePath, String destinationPath, ResourceResolver resourceResolver,
PageManager pageManager) {
copyResource(sourcePath + ASSET_PERFORMANCE_NODE_RELATIVE_PATH,
destinationPath + ASSET_PERFORMANCE_NODE_RELATIVE_PATH, resourceResolver, pageManager);
copyResource(sourcePath + ASSET_USAGE_NODE_RELATIVE_PATH, destinationPath + ASSET_USAGE_NODE_RELATIVE_PATH,
resourceResolver, pageManager);
}
private static void copyResource(String sourcePath, String destinationPath, ResourceResolver resourceResolver,
PageManager pageManager) {
Resource sourceResource = resourceResolver.getResource(sourcePath);
if (sourceResource != null) {
try {
pageManager.copy(sourceResource, destinationPath, null, false, false, false);
} catch (WCMException e) {
log.error("Unable to copy resource from " + sourcePath + " to " + destinationPath + " : {}",
e.getMessage());
}
}
}
private static void copyAllChildren(Resource sourceResource, Resource destinationResource, PageManager pageManager,
Session session) throws RepositoryException, WCMException {
if (sourceResource != null && destinationResource != null) {
Iterable childList = sourceResource.getChildren();
String destinationResourcePath = destinationResource.getPath();
for (Resource child : childList) {
String destinationChildPath = destinationResourcePath + "/" + child.getName();
pageManager.copy(child, destinationChildPath, null, false, false, false);
}
session.save();
}
}
private static void deleteAllChildren(Resource resource, Session session) throws RepositoryException {
if (resource != null) {
Iterable childList = resource.getChildren();
for (Resource child : childList) {
Node childNode = child.adaptTo(Node.class);
if (childNode != null) {
childNode.remove();
} else {
log.warn("Resource not able to adaptTo Node object while deleting the children:" + resource.getPath());
}
}
}
session.save();
}
/**
* Removes all asset renditions contained in the resource.
* If resource is a folder, then all its folders are navigated recursively to delete asset renditions.
* @param resource resource
*/
private static void removeAllRenditionsInsideResource(Resource resource) throws RepositoryException {
Iterator assets = DamUtil.getAssets(resource);
while (assets.hasNext()) {
Asset asset = assets.next();
if (!isContentFragment(asset)) {
List renditions = asset.getRenditions();
for (Rendition rendition : renditions) {
String name = rendition.getName();
if (!name.equals(DamConstants.ORIGINAL_FILE)) {
asset.removeRendition(name);
}
}
}
}
}
private static boolean isContentFragment(Asset asset) throws RepositoryException {
try {
Node assetNode = asset.adaptTo(Node.class);
Node jcrNode = assetNode;
if (assetNode != null && assetNode.hasNode(JCR_CONTENT)){
jcrNode = assetNode.getNode(JCR_CONTENT);
}
if (jcrNode != null && jcrNode.hasProperty(CONTENT_FRAGMENT)) {
return jcrNode.getProperty(CONTENT_FRAGMENT).getBoolean();
}
return false;
} catch (RepositoryException e) {
log.error("Error while checking if asset is a content fragment", e);
return false;
}
}
public static boolean isSmartAssetUpdateRequired(Asset sourceAsset, Asset destinationAsset) {
if (sourceAsset == null || destinationAsset == null) {
return false;
}
Resource sourceResource = sourceAsset.adaptTo(Resource.class);
Resource destResource = destinationAsset.adaptTo(Resource.class);
boolean bRetVal = false;
if (sourceResource != null && destResource != null) {
// now check the modified time
Resource sourceContentResource = sourceResource.getChild(JcrConstants.JCR_CONTENT);
Resource destContentResource = destResource.getChild(JcrConstants.JCR_CONTENT);
if (sourceContentResource == null) {
sourceContentResource = sourceResource;
}
if (destContentResource == null) {
destContentResource = destResource;
}
Calendar sourceLastModified = getNodeLastModifiedTime(sourceContentResource);
Calendar lastTranslationUpdate =
getCalendarAttribute(destContentResource, ATTRIBUTE_CQ_TRANSLATION_LAST_UPDATE);
if (lastTranslationUpdate != null) {
if (sourceLastModified != null) {
bRetVal =
(sourceLastModified.getTimeInMillis() - lastTranslationUpdate.getTimeInMillis()) > MAX_DIFF_MILLISECOND_CHANGED;
}
} else {
bRetVal = true; // no translation done till now
}
}
return bRetVal;
}
@Deprecated
/**
*@deprecated since 6.2, use
*{@link #addSmartAssetUpdateSource(Asset, String)} instead
*/
public static void addSmartAssetUpdateFlag(Asset destinationAsset) throws RepositoryException {
throw new UnsupportedOperationException("This API has been deprecated.Please use addSmartAssetUpdateSource(Asset, String) instead.");
}
public static void addSmartAssetUpdateSource(Asset destinationAsset, String sourcePath) throws RepositoryException {
if (destinationAsset == null || sourcePath == null) {
return;
}
Node assetNode = destinationAsset.adaptTo(Node.class);
if (assetNode != null) {
if (!assetNode.hasNode(JcrConstants.JCR_CONTENT)) {
assetNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node assetContentNode = assetNode.getNode(JcrConstants.JCR_CONTENT);
assetContentNode.setProperty(ATTRIBUTE_SMART_ASSET_UPDATE_SOURCE, sourcePath);
} else {
log.warn("Asset not able to adaptTo Node object while adding smart assets update source:" +
destinationAsset.getPath());
}
}
private static void addSmartAssetUpdateProperty(Asset destinationAsset, boolean value) throws RepositoryException {
if (destinationAsset == null) {
return;
}
Node assetNode = destinationAsset.adaptTo(Node.class);
if (assetNode != null) {
if (!assetNode.hasNode(JcrConstants.JCR_CONTENT)) {
assetNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node assetContentNode = assetNode.getNode(JcrConstants.JCR_CONTENT);
assetContentNode.setProperty(ATTRIBUTE_SMART_ASSET_UPDATE_REQUIRED, value);
} else {
log.warn("Asset not able to adaptTo Node object while adding smart assets update property:" +
destinationAsset.getPath());
}
}
private static void addExtractMetadataPropertyForAsset(Asset asset, boolean bExtractMetadata) throws RepositoryException {
Node assetNode = asset.adaptTo(Node.class);
if (assetNode != null) {
if (!assetNode.hasNode(JcrConstants.JCR_CONTENT)) {
assetNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_UNSTRUCTURED);
}
Node assetContentNode = assetNode.getNode(JcrConstants.JCR_CONTENT);
assetContentNode.setProperty(ATTRIBUTE_EXTRACT_METADATA, bExtractMetadata);
} else {
log.warn("Asset not able to adaptTo Node object while adding smart assets update property:" +
asset.getPath());
}
}
/**
* Creates language copy of an asset
*
* @param resourceResolver
* @param pageManagerFactory
* @param sourcePath
* @param targetLanguageCode
* @return path of created language copy or null if language copy is already exists and does not require translation.
*/
private static String createLanguageCopy(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final String targetLanguageCode) {
String[] targetLanguageCodeArray = {targetLanguageCode};
List languageCopyPathArray = createLanguageCopy(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodeArray);
if (null != languageCopyPathArray && languageCopyPathArray.size() == 1) {
return languageCopyPathArray.get(0);
}
return null;
}
/**
* This method creates language copy of an asset/folder and its source(for example psd for jpeg). Information about
* language copy which triggered translation is added in case temporary asset translation is required. Finally,
* relations are changed with their language copies.
*
* @param resourceResolver
* @param pageManagerFactory
* @param sourcePath - source for creating language copy
* @param targetLanguageCodes - array of language codes
* @return list of created language copies
*/
public static List createLanguageCopyWithAssetRelations(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final String[] targetLanguageCodes)
throws RepositoryException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
if (null == sourceResource) {
//returning empty array list for backward compatibility
return new ArrayList();
}
//check for asset
if (null != sourceResource.adaptTo(Asset.class) && isCreateLangCopyForRFLResource(sourceResource, resourceResolver)) {
return createLanguageCopyWithAssetRelationsForAsset(resourceResolver, pageManagerFactory,
sourcePath, targetLanguageCodes);
}
//check for asset folder
return checkAndCreateLanguageCopyWithAssetRelationsForFolder(resourceResolver, pageManagerFactory,
sourceResource, sourcePath, targetLanguageCodes);
}
private static List createLanguageCopyWithAssetRelations(final ResourceResolver resourceResolver, final PageManagerFactory pageManagerFactory,
final String sourcePath, final String[] targetLanguageCodes, HashMap> processedAssets)
throws RepositoryException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
if (null == sourceResource) {
return new ArrayList();
}
if (null != sourceResource.adaptTo(Asset.class) && isCreateLangCopyForRFLResource(sourceResource, resourceResolver)) {
return createLanguageCopyWithAssetRelationsForAsset(resourceResolver, pageManagerFactory,
sourcePath, targetLanguageCodes, processedAssets);
}
return checkAndCreateLanguageCopyWithAssetRelationsForFolder(resourceResolver, pageManagerFactory,
sourceResource, sourcePath, targetLanguageCodes);
}
private static List checkAndCreateLanguageCopyWithAssetRelationsForFolder(
final ResourceResolver resourceResolver, final PageManagerFactory pageManagerFactory, final Resource sourceResource,
final String sourcePath, final String[] targetLanguageCodes)
throws RepositoryException {
Node sourceNode = sourceResource.adaptTo(Node.class);
if (null != sourceNode && sourceNode.isNodeType(JcrConstants.NT_FOLDER)) {
return createLanguageCopyWithAssetRelationsForNTFolder(resourceResolver, pageManagerFactory,
sourcePath, targetLanguageCodes);
}
//return empty array list for backward compatibility
return new ArrayList();
}
private static String createLanguageCopyWithAssetRelations(final String sourcePath, final String targetLanguageCode,
final ResourceResolver resourceResolver, final PageManagerFactory pageManagerFactory, HashMap> processedAssets)
throws RepositoryException {
String[] languageArray = {targetLanguageCode};
List languageCopyList = createLanguageCopyWithAssetRelations(resourceResolver, pageManagerFactory,
sourcePath, languageArray, processedAssets);
if (languageCopyList != null && languageCopyList.size() == 1) {
return languageCopyList.get(0);
}
return null;
}
private static void adjustDerivedAndRemoveOthersRelationsForSourceAssetsLC (List relatedSourceAssets, String newDerivedAssetPath,
String oldDerivedAssetPath, ResourceResolver resourceResolver) {
String oldLanguageRoot = getLanguageRootLocale(oldDerivedAssetPath);
for(Asset sourceDamAsset: relatedSourceAssets) {
String targetLanguageCode = getLanguageRootLocale(newDerivedAssetPath);
String sourceAssetLCPath = findLanguageCopyPathWithAutoCreatedRoots(sourceDamAsset.getPath(),
targetLanguageCode, resourceResolver);
if (sourceAssetLCPath != null) {
Resource sourceAssetLCResource = resourceResolver.getResource(sourceAssetLCPath);
if (sourceAssetLCResource != null) {
com.adobe.granite.asset.api.Asset sourceAssetLC = sourceAssetLCResource.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (sourceAssetLC != null) {
// First remove derived relations that point to old language copies
removeAssetRelationWithLanguageCode(sourceAssetLC, ATTRIBUTE_ASSET_DERIVED_RELATION, oldLanguageRoot);
// Add new derived relation for the source asset
adjustAssetRelations(sourceAssetLC, ATTRIBUTE_ASSET_DERIVED_RELATION, oldDerivedAssetPath, newDerivedAssetPath);
// Delete the others relation for the source asset
removeAssetRelation(sourceAssetLC, ATTRIBUTE_ASSET_OTHERS_RELATION);
}
}
} else {
log.debug("No source assets language copy path found for asset: " + sourceDamAsset.getPath());
}
}
}
public static List createLanguageCopyWithAssetRelationsForAsset(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final String[] targetLanguageCodes)
throws RepositoryException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
List createdVariantCopies = new ArrayList();
if (null != sourceResource) {
createdVariantCopies = createLanguageCopyWithRelationsForAsset(resourceResolver,
pageManagerFactory, sourcePath, sourceResource, targetLanguageCodes);
Asset sourceAsset = sourceResource.adaptTo(Asset.class);
if (sourceAsset != null && isContentFragment(sourceAsset)) {
try {
//commit changes to get variations by query. todo: remove once this is fixed
resourceResolver.commit();
HashMap> processedAssets = new HashMap<>();
for (String targetLanguageCode : targetLanguageCodes) {
HashSet processedAssetList = new HashSet<>();
processedAssetList.add(sourceAsset.getPath());
processedAssets.put(targetLanguageCode, processedAssetList);
}
createAndReplaceLanguageCopyForEmbeddedAssets(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes, processedAssets);
} catch (Exception e) {
log.error("Could not create language copy for embedded assets. {}", e);
}
}
}
return createdVariantCopies;
}
private static List createLanguageCopyWithAssetRelationsForAsset(final ResourceResolver resourceResolver, final PageManagerFactory pageManagerFactory, final String sourcePath,
final String[] targetLanguageCodes, HashMap> processedAssets)
throws RepositoryException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
List createdVariantCopies = new ArrayList();
if (null != sourceResource) {
createdVariantCopies = createLanguageCopyWithRelationsForAsset(resourceResolver,
pageManagerFactory, sourcePath, sourceResource, targetLanguageCodes);
Asset sourceAsset = sourceResource.adaptTo(Asset.class);
if (sourceAsset != null && isContentFragment(sourceAsset)) {
try {
resourceResolver.commit();
createAndReplaceLanguageCopyForEmbeddedAssets(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes, processedAssets);
} catch (Exception e) {
log.error("Could not create language copy for embedded assets. {}", e);
}
}
}
return createdVariantCopies;
}
private static List createLanguageCopyWithRelationsForAsset(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final Resource sourceResource, final String[] targetLanguageCodes)
throws RepositoryException {
List createdVariantCopies = new ArrayList();
if (null != sourceResource) {
String sourceResourcePath = sourceResource.getPath();
List relatedSourceAssets = getRelatedAssets(sourceResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
List relatedLinkedAssets = getRelatedAssets(sourceResource, ATTRIBUTE_ASSET_LINKS_RELATION);
if (!relatedSourceAssets.isEmpty() || !relatedLinkedAssets.isEmpty()) {
for (int languageIndex = 0; languageIndex < targetLanguageCodes.length; languageIndex++) {
TranslationCategory translationCategory = getTranslationCategoryForAssetAndItsRelations(sourcePath,
targetLanguageCodes[languageIndex], resourceResolver);
switch (translationCategory) {
case TEMPORARY:
//Temporary Language copies are required
createMissingDestinationLanguageCopies(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes[languageIndex]);
String languageCopyPath = findLanguageCopyPathWithAutoCreatedRoots(sourcePath,
targetLanguageCodes[languageIndex], resourceResolver);
if (languageCopyPath != null) {
Resource languageCopyPathResource = resourceResolver.getResource(languageCopyPath);
if (languageCopyPathResource != null) {
Asset destinationAsset = languageCopyPathResource.adaptTo(Asset.class);
addSmartAssetUpdateSource(destinationAsset, sourcePath);
addSmartAssetUpdateProperty(destinationAsset, true);
createdVariantCopies.add(languageCopyPath);
}
} else {
log.warn("Language copy path not found for source path: " + sourcePath +
" and target language:" + targetLanguageCodes[languageIndex]);
}
break;
case DESTINATION:
//Destination Language copy needs to be created or updated.
String variantLanguageCopyPath = createOrGetLanguageCopy(resourceResolver,
pageManagerFactory, sourcePath, targetLanguageCodes[languageIndex]);
Resource variantLanguageCopyResource =
resourceResolver.getResource(variantLanguageCopyPath);
if (variantLanguageCopyResource != null) {
com.adobe.granite.asset.api.Asset graniteDestinationAsset = variantLanguageCopyResource
.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (graniteDestinationAsset != null) {
createRelationLanguageCopy(ATTRIBUTE_ASSET_SOURCE_RELATION, graniteDestinationAsset,
relatedSourceAssets, targetLanguageCodes[languageIndex], resourceResolver,
pageManagerFactory);
// Adjust the derived, others relations for the source assets
adjustDerivedAndRemoveOthersRelationsForSourceAssetsLC(relatedSourceAssets, variantLanguageCopyPath,
sourceResourcePath, resourceResolver);
// Delete the others relation for destination asset
removeAssetRelation(graniteDestinationAsset, ATTRIBUTE_ASSET_OTHERS_RELATION);
createRelationLanguageCopy(ATTRIBUTE_ASSET_LINKS_RELATION, graniteDestinationAsset,
relatedLinkedAssets, targetLanguageCodes[languageIndex], resourceResolver,
pageManagerFactory);
createRelationLanguageCopyForSourceRelations(ATTRIBUTE_ASSET_LINKS_RELATION,
relatedSourceAssets, targetLanguageCodes[languageIndex],
resourceResolver, pageManagerFactory);
createdVariantCopies.add(variantLanguageCopyPath);
}
} else {
log.warn("Variant language copy resource not found for path: " + variantLanguageCopyPath);
}
break;
case NONE:
String tempLanguageCopyPath = findLanguageCopyPathWithAutoCreatedRoots(sourcePath,
targetLanguageCodes[languageIndex], resourceResolver);
if (tempLanguageCopyPath != null) {
Resource tempLanguageCopyResource = resourceResolver.getResource(tempLanguageCopyPath);
if (tempLanguageCopyResource != null) {
Asset tempDestinationAsset = tempLanguageCopyResource.adaptTo(
Asset.class);
addSmartAssetUpdateProperty(tempDestinationAsset, false);
createdVariantCopies.add(tempLanguageCopyPath);
}
} else {
log.warn("Language copy path not found for source path: " + sourcePath +
" and target language:" + targetLanguageCodes[languageIndex]);
}
break;
}
}
} else {
createdVariantCopies = createLanguageCopy(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes);
}
//todo add destination if required
Asset sourceAsset = sourceResource.adaptTo(Asset.class);
if(sourceAsset != null && isContentFragment(sourceAsset)) {
try {
createOrUpdateLanguageCopyForAssociatedContent(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes);
} catch (Exception e) {
log.error("Could not create language copy for associated content. {}", e);
}
}
}
return createdVariantCopies;
}
private static void createAndReplaceLanguageCopyForEmbeddedAssets(ResourceResolver resourceResolver, PageManagerFactory pageManagerFactory,
String sourcePath, String[] targetLanguageCodes, HashMap> processedAssets)
throws RepositoryException, IOException, WCMException, ContentFragmentException {
String sourceLanguage = getLanguageRootLocale(sourcePath);
for (String targetLanguageCode : targetLanguageCodes) {
String languageCopyPath = findLanguageCopyPathWithAutoCreatedRoots(sourcePath, targetLanguageCode, resourceResolver);
if (null != languageCopyPath && isTranslateInlineMediaAssets(languageCopyPath,
resourceResolver)) {
if (!temporaryAssetSourcePropertyExist(languageCopyPath, resourceResolver)) {
boolean bReplacementRequired = createLanguageCopyForEmbeddedAssets(languageCopyPath, sourceLanguage, targetLanguageCode,
resourceResolver, pageManagerFactory, processedAssets);
if (bReplacementRequired) {
Resource res = resourceResolver.getResource(languageCopyPath);
if (res != null) {
Node languageNode = res.adaptTo(Node.class);
if(languageNode != null) {
CFEmbeddedAssetUtil.updateEmbeddedAssetReferences(languageNode, targetLanguageCode, resourceResolver, true);
}
} else {
log.warn("Resource not found for the path: " + languageCopyPath);
}
}
} else {
//create language copies or mark for updates for source asset
createLanguageCopyForEmbeddedAssets(sourcePath, sourceLanguage, targetLanguageCode, resourceResolver,
pageManagerFactory, processedAssets);
}
}
}
}
private static boolean temporaryAssetSourcePropertyExist(String assetpath, ResourceResolver resourceResolver) throws
RepositoryException {
boolean retVal = false;
Resource resource = resourceResolver.getResource(assetpath);
if (null != resource) {
Node node = resource.adaptTo(Node.class);
if (node != null && getUpdateAssetNodeSourcePath(node) != null) {
retVal = true;
}
}
return retVal;
}
private static boolean createLanguageCopyForEmbeddedAssets(String contentFragmentPath, String sourceLanguageCode, String targetLanguageCode,
ResourceResolver resourceResolver, PageManagerFactory pageManagerFactory, HashMap> processedAssets)
throws RepositoryException, IOException {
Set embeddedAssets = CFEmbeddedAssetUtil.getEmbeddedAssets(contentFragmentPath, resourceResolver, true);
boolean bReplacementRequired = false;
getLanguageRootLocale(contentFragmentPath);
for (Asset embeddedAsset : embeddedAssets) {
if (processedAssets.get(targetLanguageCode).contains(embeddedAsset.getPath())) {
if (!targetLanguageCode.equals(getLanguageRootLocale(embeddedAsset.getPath()))) {
bReplacementRequired = true;
}
continue;
}
processedAssets.get(targetLanguageCode).add(embeddedAsset.getPath());
String embeddedAssetPath = embeddedAsset.getPath();
String sourceEmbeddedAssetPath;
String languageRootLocale = getLanguageRootLocale(embeddedAssetPath);
if (languageRootLocale != null) {
if (!targetLanguageCode.equals(languageRootLocale)) {
sourceEmbeddedAssetPath = embeddedAssetPath;
bReplacementRequired = true;
} else {
sourceEmbeddedAssetPath = findLanguageCopyPathWithAutoCreatedRoots(embeddedAssetPath, sourceLanguageCode,
resourceResolver);
}
if (sourceEmbeddedAssetPath != null) {
createLanguageCopyWithAssetRelations(sourceEmbeddedAssetPath, targetLanguageCode, resourceResolver,
pageManagerFactory, processedAssets);
}
} else {
log.info("Not Creating Language copy because Language root does not exist for Embedded Asset {} ", embeddedAsset.getPath());
}
}
return bReplacementRequired;
}
private static void createOrUpdateLanguageCopyForAssociatedContent(ResourceResolver resourceResolver,
PageManagerFactory pageManagerFactory, String sourcePath, String[] targetLanguageCodes)
throws RepositoryException, PersistenceException, WCMException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
if (null != sourceResource) {
Node sourceNode = sourceResource.adaptTo(Node.class);
if (sourceNode != null) {
targetLanguageCodes = getAssociatedContentTranslationLanguages(sourceResource, targetLanguageCodes,
resourceResolver);
ArrayList associatedAssets = getContentFragmentAssociatedAssets(sourceNode, resourceResolver);
for (Asset asset : associatedAssets) {
createLanguageCopyWithAssetRelations(resourceResolver, pageManagerFactory, asset.getPath(),
targetLanguageCodes);
}
createOrUpdateLanguageCopyForAssociatedContentNode(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes);
} else {
log.warn("Resource not able to adaptTo Node object: ", sourceResource.getPath());
}
} else {
log.error("Could not create language copy for associated content. Resource nt found at path {}",
sourcePath);
}
}
private static String[] getAssociatedContentTranslationLanguages(Resource sourceResource,
String[] targetLanguageCodes, ResourceResolver resourceResolver) {
ArrayList applicableLanguages = new ArrayList();
String sourcePath = sourceResource.getPath();
for (String targetLanguageCode : targetLanguageCodes) {
String lcPath = findLanguageCopyPathWithAutoCreatedRoots(sourcePath, targetLanguageCode, resourceResolver);
if (null != lcPath) {
Resource lcResource = resourceResolver.getResource(lcPath);
if (isTranslateAssociatedContent(lcResource, resourceResolver)) {
applicableLanguages.add(targetLanguageCode);
}
}
}
return applicableLanguages.toArray(new String[applicableLanguages.size()]);
}
private static void createOrUpdateLanguageCopyForAssociatedContentNode(ResourceResolver resourceResolver,
PageManagerFactory pageManagerFactory, String sourcePath, String[] targetLanguageCodes)
throws PersistenceException, WCMException, RepositoryException {
createOrUpdateLanguageCopyForAssociatedContentNode(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCodes, "");
}
private static void createOrUpdateLanguageCopyForAssociatedContentNode(ResourceResolver resourceResolver,
PageManagerFactory pageManagerFactory, String sourcePath, String[] targetLanguageCodes, String prefixPath)
throws PersistenceException, WCMException, RepositoryException {
Resource sourceAssociatedContentResource = getAssociatedContentResource(sourcePath, resourceResolver);
if (sourceAssociatedContentResource == null) {
return;
}
PageManager pageManager = pageManagerFactory.getPageManager(resourceResolver);
for (String targetLanguageCode : targetLanguageCodes) {
ResourceCollection destinationAssociatedContents = findAssociatedContentLanguageCopy(sourcePath, prefixPath,
targetLanguageCode, resourceResolver);
if (null == destinationAssociatedContents) {
continue;
}
Iterator collectionResources = getResourcesFromCollection(sourceAssociatedContentResource);
if (null == collectionResources) {
continue;
}
while (collectionResources.hasNext()) {
Resource sourceCollectionResource = collectionResources.next();
createOrUpdateCollectionLanguageCopy(sourceCollectionResource, targetLanguageCode,
destinationAssociatedContents, resourceResolver, pageManager);
//nested collections
createLCForNestedCollections(sourceCollectionResource, targetLanguageCode, resourceResolver,
pageManager);
}
}
}
private static void createLCForNestedCollections(Resource sourceCollectionResource, String targetLanguageCode,
ResourceResolver resourceResolver, PageManager pageManager) throws RepositoryException, WCMException,
PersistenceException {
HashSet nestedCollections = new HashSet();
createLCForNestedCollections(sourceCollectionResource, targetLanguageCode, resourceResolver, pageManager,
nestedCollections);
}
private static void createLCForNestedCollections(Resource sourceCollectionResource, String targetLanguageCode,
ResourceResolver resourceResolver, PageManager pageManager, HashSet updatedCollections)
throws RepositoryException, WCMException, PersistenceException {
ResourceCollection sourceCollection = sourceCollectionResource.adaptTo(ResourceCollection.class);
if (sourceCollection != null) {
Iterator sourceResources = sourceCollection.getResources();
while (sourceResources.hasNext()) {
Resource sourceResource = sourceResources.next();
if (isDamCollection(sourceResource) && !updatedCollections.contains(sourceResource)) {
ResourceCollection destinationCollection = getDestinationCollection(sourceCollection.getPath(),
targetLanguageCode, resourceResolver);
createOrUpdateCollectionLanguageCopy(sourceResource, targetLanguageCode, destinationCollection,
resourceResolver, pageManager);
updatedCollections.add(sourceResource);
createLCForNestedCollections(sourceResource, targetLanguageCode, resourceResolver, pageManager,
updatedCollections);
}
}
} else {
log.warn("Resource not able to adaptTo Resource collection object: " + sourceCollectionResource.getPath());
}
}
private static boolean isDamCollection(Resource sourceResource) {
return sourceResource.isResourceType("dam/collection");
}
private static ResourceCollection getDestinationCollection(String sourceCollectionPath, String targetLanguageCode,
ResourceResolver resourceResolver) {
String destinationCollectionPath = getAssociatedContentLanguageCopyPathOrName(sourceCollectionPath,
targetLanguageCode);
Resource resource = resourceResolver.getResource(destinationCollectionPath);
if (null == resource) {
return null;
}
return resource.adaptTo(ResourceCollection.class);
}
private static ResourceCollection findAssociatedContentLanguageCopy(String sourceContentFragmentPath, String
prefixPath, String targetLanguageCode, ResourceResolver resourceResolver) throws RepositoryException {
String destinationContentFragmentPath = findLanguageCopyPathWithAutoCreatedRoots(sourceContentFragmentPath,
targetLanguageCode, resourceResolver);
Resource targetAssociatedContentResource = null;
if (null != destinationContentFragmentPath) {
destinationContentFragmentPath = prefixPath + destinationContentFragmentPath;
targetAssociatedContentResource = getAssociatedContentResource(destinationContentFragmentPath,
resourceResolver);
}
if (null != targetAssociatedContentResource) {
return targetAssociatedContentResource.adaptTo(ResourceCollection.class);
}
return null;
}
private static Iterator getResourcesFromCollection(Resource collectionResource) {
ResourceCollection associatedContentCollection = collectionResource.adaptTo(ResourceCollection.class);
if(associatedContentCollection!=null) {
return associatedContentCollection.getResources();
}
return null;
}
private static void createOrUpdateCollectionLanguageCopy(Resource sourceCollectionResource, String
targetLanguageCode, ResourceCollection destinationAssociatedContents, ResourceResolver resourceResolver,
PageManager pageManager) throws WCMException, PersistenceException, RepositoryException {
String sourceCollectionPath = sourceCollectionResource.getPath();
String targetPath = getAssociatedContentLanguageCopyPathOrName(sourceCollectionPath, targetLanguageCode);
Resource targetCollectionResource = resourceResolver.getResource(targetPath);
if (null == targetCollectionResource) {
targetCollectionResource = pageManager.copy(sourceCollectionResource, targetPath, null, false, false, true);
setProperty(targetCollectionResource, ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY, sourceCollectionPath);
Node sourceCollectionNode = sourceCollectionResource.adaptTo(Node.class);
if (null != sourceCollectionNode && sourceCollectionNode.hasProperty(JCR_TITLE)) {
String sourceCollectionName = sourceCollectionNode.getProperty(JCR_TITLE)
.getString();
String destinationCollectionName = getAssociatedContentLanguageCopyPathOrName(
sourceCollectionName, targetLanguageCode);
setProperty(targetCollectionResource, JCR_TITLE, destinationCollectionName);
}
} else {
updateExistingCollectionResource(sourceCollectionResource, targetCollectionResource, targetLanguageCode,
resourceResolver);
}
ResourceCollection collectionLanguageCopy = targetCollectionResource.adaptTo(ResourceCollection.class);
replaceCollectionResource(destinationAssociatedContents, sourceCollectionResource, targetCollectionResource,
resourceResolver);
if (collectionLanguageCopy != null) {
replaceCollectionAssetLanguageCopies(collectionLanguageCopy, targetLanguageCode, resourceResolver);
} else {
log.warn("Resource not able to adaptTo Resource collection object: " + collectionLanguageCopy.getPath());
}
}
private static void setProperty(Resource resource, String property, String value) throws RepositoryException {
Node node = resource.adaptTo(Node.class);
if (node != null) {
node.setProperty(property, value);
} else {
log.error("Resource :" + resource.getPath() +
" not able to adaptTo Node object thus skipping the update of property: " + property
+ " to value: " + value);
}
}
private static String getAssociatedContentLanguageCopyPathOrName(String source, String targetLanguageCode) {
String initial = source;
if (initial.contains("-")) {
//check if language code exists
String languageCode = initial.substring(initial.lastIndexOf("-") + 1);
Locale locale = LanguageUtil.getLocale(languageCode);
if (locale != null) {
//remove language code
initial = initial.substring(0, initial.lastIndexOf("-"));
}
}
String languageCopyPostfix = "-" + targetLanguageCode;
return initial + languageCopyPostfix;
}
private static void updateExistingCollectionResource(Resource sourceCollectionResource, Resource
targetCollectionResource, String targetLanguageCode, ResourceResolver resourceResolver) throws
PersistenceException, RepositoryException {
if (null == sourceCollectionResource || null == targetCollectionResource) {
return;
}
ResourceCollection sourceCollection = sourceCollectionResource.adaptTo(ResourceCollection.class);
ResourceCollection targetCollection = targetCollectionResource.adaptTo(ResourceCollection.class);
if(null == sourceCollection || null == targetCollection) {
return;
}
Node targetNode = targetCollectionResource.adaptTo(Node.class);
if (targetNode != null) {
targetNode.setProperty(ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY, sourceCollection.getPath());
} else {
log.error("Resource :" + targetCollectionResource.getPath() +
" not able to adaptTo Node object thus skipping the update of property: " +
ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY);
}
Iterator sourceResources = sourceCollection.getResources();
while (sourceResources.hasNext()) {
Resource sourceResource = sourceResources.next();
if (null != sourceResource.adaptTo(Asset.class) || isFolder(sourceResource)) {
Resource destinationResource = findLanguageCopyWithAutoCreatedRootsForAssetOrNTFolder(sourceResource,
targetLanguageCode, resourceResolver);
replaceCollectionResource(targetCollection, sourceResource, destinationResource, resourceResolver);
}
}
}
private static void replaceCollectionAssetLanguageCopies(ResourceCollection collectionLanguageCopy, String
targetLanguageCode, ResourceResolver resourceResolver) throws PersistenceException, RepositoryException {
Iterator resourceIterator = collectionLanguageCopy.getResources();
while (resourceIterator.hasNext()) {
Resource resource = resourceIterator.next();
if (null != resource.adaptTo(Asset.class) || isFolder(resource)) {
String currentLanguage = getLanguageRootLocale(resource.getPath());
if (null == currentLanguage || !currentLanguage.equals(targetLanguageCode)) {
Resource languageCopyResource = findLanguageCopyWithAutoCreatedRootsForAssetOrNTFolder(
resource, targetLanguageCode, resourceResolver);
if (null != languageCopyResource) {
replaceCollectionResource(collectionLanguageCopy, resource, languageCopyResource,
resourceResolver);
}
}
}
}
}
private static void replaceCollectionResource(ResourceCollection collectionLanguageCopy, Resource
sourceLanguageResource, Resource destinationLanguageResource, ResourceResolver resourceResolver)
throws PersistenceException {
collectionLanguageCopy.remove(sourceLanguageResource);
//commit changes to before adding language copy. todo: remove once this is fixed
resourceResolver.commit();
collectionLanguageCopy.add(destinationLanguageResource);
resourceResolver.commit();
}
public static List createLanguageCopyWithAssetRelationsForNTFolder(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String sourcePath, final String[] targetLanguageCodes)
throws RepositoryException {
Resource sourceResource = resourceResolver.getResource(sourcePath);
if (null != sourceResource) {
Iterator assetIterator = DamUtil.getAssets(sourceResource);
while (assetIterator.hasNext()) {
Asset nextAsset = assetIterator.next();
createLanguageCopyWithAssetRelations(resourceResolver, pageManagerFactory, nextAsset.getPath(),
targetLanguageCodes);
}
}
List createdLanguageCopies = new ArrayList();
for (String targetLanguageCode : targetLanguageCodes) {
Node targetLanguageCopy =
findLanguageCopyForNTFolderWithAutoCreatedRoots(sourcePath, targetLanguageCode, resourceResolver);
if (null != targetLanguageCopy) {
createdLanguageCopies.add(targetLanguageCopy.getPath());
}
}
return createdLanguageCopies;
}
private static void createRelationLanguageCopyForSourceRelations(String relationName,
List relatedSourceAssets, String targetLanguageCode, ResourceResolver resourceResolver,
PageManagerFactory pageManagerFactory) {
for (Asset relatedSourceAsset : relatedSourceAssets) {
Resource relatedSourceResource = relatedSourceAsset.adaptTo(Resource.class);
com.adobe.granite.asset.api.Asset graniteSourceAsset = relatedSourceAsset
.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (graniteSourceAsset != null) {
List relatedLinkedAssets = getRelatedAssets(relatedSourceResource, relationName);
Asset destinationAsset = findLanguageCopyWithAutoCreatedRoots(graniteSourceAsset.getPath(),
targetLanguageCode, resourceResolver);
if (destinationAsset != null) {
com.adobe.granite.asset.api.Asset graniteDestinationAsset = destinationAsset
.adaptTo(com.adobe.granite.asset.api.Asset.class);
createRelationLanguageCopy(relationName, graniteDestinationAsset, relatedLinkedAssets,
targetLanguageCode, resourceResolver, pageManagerFactory);
}
} else {
log.error("Asset :" + relatedSourceAsset.getPath() +
" not able to adaptTo com.adobe.granite.asset.api.Asset object.");
}
}
}
private static void createRelationLanguageCopy(String relationName, com.adobe.granite.asset.api.Asset
graniteDestinationAsset, List relatedAssets, String targetLanguageCode, ResourceResolver
resourceResolver, PageManagerFactory pageManagerFactory) {
ArrayList resetRelationPaths = new ArrayList();
for (Asset relatedSourceAsset : relatedAssets) {
String sourceRelationPath = relatedSourceAsset.getPath();
String sourceRelationLanguageCopyPath = createOrGetLanguageCopy(resourceResolver, pageManagerFactory,
sourceRelationPath, targetLanguageCode);
resetRelationPaths.add(sourceRelationLanguageCopyPath);
}
// reset the source relations for this asset
resetAssetRelations(graniteDestinationAsset, relationName, resetRelationPaths);
}
private static String createOrGetLanguageCopy(ResourceResolver resourceResolver, PageManagerFactory pageManagerFactory, String sourcePath, String targetLanguageCode) {
String languageCopyPath = createLanguageCopy(resourceResolver, pageManagerFactory, sourcePath,
targetLanguageCode);
if (languageCopyPath == null) {
languageCopyPath = findLanguageCopyPathWithAutoCreatedRoots(sourcePath, targetLanguageCode, resourceResolver);
}
return languageCopyPath;
}
private static void createMissingDestinationLanguageCopies(ResourceResolver resourceResolver, PageManagerFactory pageManagerFactory, String assetPath, String targetLanguageCode) {
if (null == findLanguageCopyPathWithAutoCreatedRoots(assetPath, targetLanguageCode, resourceResolver)) {
createLanguageCopy(resourceResolver, pageManagerFactory, assetPath, targetLanguageCode);
}
Resource assetResource = resourceResolver.getResource(assetPath);
createMissingDestinationLanguageCopiesForRelations(ATTRIBUTE_ASSET_SOURCE_RELATION, assetResource,
targetLanguageCode, resourceResolver, pageManagerFactory);
createMissingDestinationLanguageCopiesForRelations(ATTRIBUTE_ASSET_LINKS_RELATION, assetResource,
targetLanguageCode, resourceResolver, pageManagerFactory);
createMissingDestinationLanguageCopiesForRelationsOfSources(ATTRIBUTE_ASSET_LINKS_RELATION, assetResource,
targetLanguageCode, resourceResolver, pageManagerFactory);
}
private static void createMissingDestinationLanguageCopiesForRelationsOfSources(String relationName, Resource
assetResource, String targetLanguageCode, ResourceResolver resourceResolver, PageManagerFactory
pageManagerFactory) {
List relatedSourceAssets = getRelatedAssets(assetResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
for (Asset relatedSourceAsset : relatedSourceAssets) {
Resource relatedSourceResource = relatedSourceAsset.adaptTo(Resource.class);
createMissingDestinationLanguageCopiesForRelations(relationName, relatedSourceResource,
targetLanguageCode, resourceResolver, pageManagerFactory);
}
}
private static void createMissingDestinationLanguageCopiesForRelations(String relationName, Resource assetResource,
String targetLanguageCode, ResourceResolver resourceResolver, PageManagerFactory pageManagerFactory) {
List relatedAssets = getRelatedAssets(assetResource, relationName);
if (!relatedAssets.isEmpty()) {
for (Asset relatedAsset : relatedAssets) {
String relatedAssetPath = relatedAsset.getPath();
if (null == findLanguageCopyPathWithAutoCreatedRoots(relatedAssetPath, targetLanguageCode,
resourceResolver)) {
createLanguageCopy(resourceResolver, pageManagerFactory, relatedAssetPath, targetLanguageCode);
}
}
}
}
public static List getRelatedAssets(Resource resource, String relationName) {
ArrayList relatedAssets = new ArrayList();
if (null != resource) {
com.adobe.granite.asset.api.Asset graniteSourceAsset = resource
.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (null != graniteSourceAsset) {
Iterator assetRelationIterator = (Iterator) graniteSourceAsset
.listRelations(relationName);
while (assetRelationIterator.hasNext()) {
AssetRelation assetRelation = assetRelationIterator.next();
com.adobe.granite.asset.api.Asset graniteAsset = assetRelation.getAsset();
relatedAssets.add(graniteAsset.adaptTo(Asset.class));
}
}
}
return relatedAssets;
}
private static TranslationCategory getTranslationCategoryForAssetAndItsRelations(String assetPath, String
targetLanguageCode, ResourceResolver resourceResolver) throws RepositoryException {
String languageRootLocale = getLanguageRootLocale(assetPath);
if(languageRootLocale != null && languageRootLocale.equals(targetLanguageCode)) {
return TranslationCategory.NONE;
}
TranslationCategory groupCategory = TranslationCategory.NONE;
TranslationCategory currentCategory = null;
Resource sourceResource = resourceResolver.getResource(assetPath);
if (null != sourceResource) {
//check current asset
Asset assetInSourceLanguage = sourceResource.adaptTo(Asset.class);
Asset assetInDestinationLanguage = findLanguageCopyWithAutoCreatedRoots(assetPath, targetLanguageCode,
resourceResolver);
if (null != assetInDestinationLanguage) {
currentCategory = isSmartAssetUpdateRequired(assetInSourceLanguage, assetInDestinationLanguage) || isTranslationOnUpdateOnlyDisabledForAssets(assetInDestinationLanguage.getPath(), resourceResolver)
|| isTargetPathInDraftState(assetInDestinationLanguage) ?
TranslationCategory.TEMPORARY : TranslationCategory.NONE;
} else {
currentCategory = TranslationCategory.DESTINATION;
}
groupCategory = combineCategory(groupCategory, currentCategory);
if(groupCategory!=TranslationCategory.TEMPORARY){
currentCategory = getTranslationCategoryForRelation(ATTRIBUTE_ASSET_SOURCE_RELATION,
sourceResource, targetLanguageCode, resourceResolver);
groupCategory = combineCategory(groupCategory, currentCategory);
}
if(groupCategory!=TranslationCategory.TEMPORARY){
currentCategory = getTranslationCategoryForRelation(ATTRIBUTE_ASSET_LINKS_RELATION,
sourceResource, targetLanguageCode, resourceResolver);
groupCategory = combineCategory(groupCategory, currentCategory);
}
if (groupCategory!=TranslationCategory.TEMPORARY) {
currentCategory = getTranslationCategoryForRelationOfSources(ATTRIBUTE_ASSET_LINKS_RELATION,
sourceResource, targetLanguageCode, resourceResolver);
groupCategory = combineCategory(groupCategory, currentCategory);
}
}
return groupCategory;
}
private static TranslationCategory combineCategory(TranslationCategory c1, TranslationCategory c2) {
if (c1 == TranslationCategory.TEMPORARY || c2 == TranslationCategory.TEMPORARY) {
//any one temporary --> make the entire group temporary
return TranslationCategory.TEMPORARY;
}
if (c1 == TranslationCategory.NONE && c2 == TranslationCategory.NONE) {
//both doesn't need translation
return TranslationCategory.NONE;
}
//at least one DESTINATION and other NONE/DESTINATION
return TranslationCategory.DESTINATION;
}
private static TranslationCategory getTranslationCategoryForRelationOfSources(String relationName, Resource
relaterResource, String targetLanguageCode, ResourceResolver resourceResolver) throws RepositoryException {
TranslationCategory groupCategory = TranslationCategory.NONE;
List relatedSourceAssets = getRelatedAssets(relaterResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
for (Asset relatedSourceAsset : relatedSourceAssets) {
Resource relatedSourceResource = relatedSourceAsset.adaptTo(Resource.class);
TranslationCategory currentCategory = getTranslationCategoryForRelation(relationName, relatedSourceResource,
targetLanguageCode, resourceResolver);
groupCategory = combineCategory(groupCategory, currentCategory);
}
return groupCategory;
}
private static TranslationCategory getTranslationCategoryForRelation(String relationName, Resource sourceResource,
String targetLanguageCode, ResourceResolver resourceResolver) throws RepositoryException {
TranslationCategory translationCategory = TranslationCategory.NONE;
List relatedAssetsInSourceLanguage = getRelatedAssets(sourceResource, relationName);
for (Asset relatedAssetInSourceLanguage : relatedAssetsInSourceLanguage) {
String relatedAssetInSourceLanguagePath = relatedAssetInSourceLanguage.getPath();
Asset relatedAssetInDestinationLanguage = findLanguageCopyWithAutoCreatedRoots(
relatedAssetInSourceLanguagePath, targetLanguageCode, resourceResolver);
if (null != relatedAssetInDestinationLanguage) {
if (isSmartAssetUpdateRequired(relatedAssetInSourceLanguage, relatedAssetInDestinationLanguage) ||
isTranslationOnUpdateOnlyDisabledForAssets(relatedAssetInDestinationLanguage.getPath(), resourceResolver) ||
isTargetPathInDraftState(relatedAssetInDestinationLanguage)) {
translationCategory = TranslationCategory.TEMPORARY;
break;
}
} else {
translationCategory = TranslationCategory.DESTINATION;
}
}
return translationCategory;
}
/**
* Removes asset relations with given language code
* Useful for removing relations of an {@link com.adobe.granite.asset.api.Asset}
*
* @param graniteAsset Asset whose relations have to ve removed/added.
* @param relationName name of the relation.
* @param languageRoot the language root of the relations to remove
*/
private static void removeAssetRelationWithLanguageCode(com.adobe.granite.asset.api.Asset graniteAsset,
String relationName, String languageRoot) {
List relations = getRelationsPathList(graniteAsset, relationName);
String relationLanguageRoot;
for (String relation: relations) {
relationLanguageRoot = getLanguageRootLocale(relation);
if (relationLanguageRoot != null && relationLanguageRoot.equals(languageRoot)) {
graniteAsset.removeRelation(relationName, relation);
}
}
}
/**
* Removes relation passed as unlinkRelation followed by adding relation passed as linkRelation.
* Useful for replacing relations of an {@link com.adobe.granite.asset.api.Asset}.
*
* @param graniteAsset Asset whose relations have to ve removed/added.
* @param relationName name of the relation.
* @param unlinkRelation relations to be removed.
* @param linkRelation relations to be added.
*/
private static void adjustAssetRelations(com.adobe.granite.asset.api.Asset graniteAsset, String relationName,
String unlinkRelation, String linkRelation) {
List relations = getRelationsPathList(graniteAsset, relationName);
if (relations.contains(unlinkRelation)) {
graniteAsset.removeRelation(relationName, unlinkRelation);
}
if (!relations.contains(linkRelation)) {
graniteAsset.addRelation(relationName, linkRelation);
}
}
/**
* Removes relations of any type of a {@link com.adobe.granite.asset.api.Asset}.
* @param graniteAsset Asset whose relations have to ve removed/added.
* @param relationName name of the relation to remove
*/
private static void removeAssetRelation (com.adobe.granite.asset.api.Asset graniteAsset, String relationName) {
if (graniteAsset != null && graniteAsset.listRelations(relationName).hasNext()) {
graniteAsset.removeRelation(relationName);
}
}
private static void resetAssetRelations(com.adobe.granite.asset.api.Asset graniteAsset, String relationName,
ArrayList linkRelations) {
if (graniteAsset.listRelations(relationName).hasNext()) {
graniteAsset.removeRelation(relationName);
}
for (String linkRelation : linkRelations) {
graniteAsset.addRelation(relationName, linkRelation);
}
}
private static List getRelationsPathList(com.adobe.granite.asset.api.Asset graniteAsset, String relation) {
Iterator> relationIterator = graniteAsset.listRelations(relation);
List relationsList = new ArrayList();
while (relationIterator.hasNext()) {
AssetRelation assetRelation = (AssetRelation) relationIterator.next();
com.adobe.granite.asset.api.Asset asset = assetRelation.getAsset();
String relationPath = asset.getPath();
relationsList.add(relationPath);
}
return relationsList;
}
private static String getUpdateAssetNodeSourcePath(Node node) throws RepositoryException {
if (node != null && node.isNodeType(DamConstants.NT_DAM_ASSET)) {
if (node.hasNode(JcrConstants.JCR_CONTENT)) {
Node assetContentNode = node.getNode(JcrConstants.JCR_CONTENT);
if (assetContentNode.hasProperty(ATTRIBUTE_SMART_ASSET_UPDATE_SOURCE)) {
return assetContentNode.getProperty(ATTRIBUTE_SMART_ASSET_UPDATE_SOURCE).getValue().getString();
}
}
}
return null;
}
/*
* Return the temporary language copy of asset as a resource, where the temporary language copy
* resides inside the prefix path
*/
private static Resource findTemporaryLanguageCopy (Asset asset, String prefixPath, ResourceResolver resourceResolver) {
String tempLCPath = prefixPath + '/' + asset.getPath();
Resource tempLCResource = resourceResolver.getResource(tempLCPath);
if (tempLCResource != null) {
return tempLCResource;
}
return null;
}
/*
* For each temporary copy of source asset, add the new derived relation and remove the others relations
*/
private static void adjustDerivedAndRemoveOthersForSourceAssetsTempLC(List relatedSourceAssets, String destinationAssetPath,
String prefixPath, String sourceLanguageRoot, ResourceResolver resourceResolver) {
for (Asset sourceDamAsset: relatedSourceAssets) {
Resource sourceDamAssetTempLC = findTemporaryLanguageCopy(sourceDamAsset, prefixPath, resourceResolver);
if (sourceDamAssetTempLC != null) {
com.adobe.granite.asset.api.Asset sourceGraniteAssetTempLC = sourceDamAssetTempLC.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (sourceGraniteAssetTempLC != null) {
// First remove relations that point to old language copies
removeAssetRelationWithLanguageCode(sourceGraniteAssetTempLC, ATTRIBUTE_ASSET_DERIVED_RELATION, sourceLanguageRoot);
// Add this new derived relation
sourceGraniteAssetTempLC.addRelation(ATTRIBUTE_ASSET_DERIVED_RELATION, destinationAssetPath);
// Remove the others relation
removeAssetRelation(sourceGraniteAssetTempLC, ATTRIBUTE_ASSET_OTHERS_RELATION);
}
}
}
}
private static boolean createUpdateLanguageCopyWithAssetRelationsRequired(final ResourceResolver resourceResolver,
final String destinationPath) throws RepositoryException {
Resource destinationResource = resourceResolver.resolve(destinationPath);
if (null != destinationResource) {
Node destinationNode = destinationResource.adaptTo(Node.class);
String updateAssetSourcePath = getUpdateAssetNodeSourcePath(destinationNode);
if (null != updateAssetSourcePath) {
return true;
}
}
return false;
}
/**
* This method creates temporary language copy of an asset/folder and its source(for example psd for jpeg) in case
* temporary asset translation is required. Finally, relations are changed with their temporary copies.
*
* @param resourceResolver
* @param pageManagerFactory
* @param destinationPath - source for creating language copy
* @param targetLanguageCode - destination language code
* @param prefixPath - Root path where language copies are created
* @return created variant temporary language copy path if created, otherwise returns destinationPath
*/
public static String createUpdateLanguageCopyWithAssetRelations(final ResourceResolver resourceResolver,
final PageManagerFactory pageManagerFactory, final String destinationPath, final String targetLanguageCode,
String prefixPath) throws RepositoryException {
boolean updateRequired = createUpdateLanguageCopyWithAssetRelationsRequired(resourceResolver, destinationPath);
String variantPath = destinationPath;
if (updateRequired) {
Resource destinationResource = resourceResolver.resolve(destinationPath);
List relatedSourceAssets = getRelatedAssets(destinationResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
if (null != destinationResource) {
Node destinationNode = destinationResource.adaptTo(Node.class);
String updateAssetSourcePath = getUpdateAssetNodeSourcePath(destinationNode);
String updateAssetLanguageLocale = getLanguageRootLocale(updateAssetSourcePath);
variantPath = createUpdateLanguageCopy(resourceResolver, pageManagerFactory, updateAssetSourcePath,
targetLanguageCode, prefixPath);
createUpdateLanguageCopyForRelation(ATTRIBUTE_ASSET_SOURCE_RELATION, updateAssetSourcePath, variantPath,
targetLanguageCode, prefixPath, resourceResolver, pageManagerFactory);
//Adjust the derived, others relations for the source assets
adjustDerivedAndRemoveOthersForSourceAssetsTempLC(relatedSourceAssets, destinationPath, prefixPath,
updateAssetLanguageLocale, resourceResolver);
createUpdateLanguageCopyForRelation(ATTRIBUTE_ASSET_LINKS_RELATION, updateAssetSourcePath, variantPath,
targetLanguageCode, prefixPath, resourceResolver, pageManagerFactory);
createUpdateLanguageCopyForRelationOfSources(ATTRIBUTE_ASSET_LINKS_RELATION, updateAssetSourcePath,
variantPath, targetLanguageCode, prefixPath, resourceResolver, pageManagerFactory);
//update Content Fragment Associated Collection
Asset destinationAsset = destinationResource.adaptTo(Asset.class);
if (destinationAsset != null && isContentFragment(destinationAsset)) {
String[] targetLanguageCodeArray = {targetLanguageCode};
try {
createOrUpdateLanguageCopyForAssociatedContentNode(resourceResolver, pageManagerFactory,
updateAssetSourcePath, targetLanguageCodeArray, prefixPath);
} catch (Exception e) {
log.error("could not create or update langauge copy for associated content node for {}",
prefixPath + destinationPath, e);
}
}
}
}
return variantPath;
}
private static void createUpdateLanguageCopyForRelationOfSources(String relationName, String
updateAssetSourcePath, String variantPath, String targetLanguageCode, String prefixPath, ResourceResolver
resourceResolver, PageManagerFactory pageManagerFactory) {
Resource updateAssetSourceResource = resourceResolver.getResource(updateAssetSourcePath);
List relatedSources = getRelatedAssets(updateAssetSourceResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
for (Asset relatedSource : relatedSources) {
String relatedSourcePath = relatedSource.getPath();
String LCofRelatedSource = findLanguageCopyPathWithAutoCreatedRoots(relatedSourcePath,
targetLanguageCode, resourceResolver);
String tempLCofRelatedSource = prefixPath + LCofRelatedSource;
createUpdateLanguageCopyForRelation(relationName, relatedSourcePath, tempLCofRelatedSource,
targetLanguageCode, prefixPath, resourceResolver, pageManagerFactory);
}
}
private static void createUpdateLanguageCopyForRelation(String relationName, String updateAssetSourcePath, String
variantPath, String targetLanguageCode, String prefixPath, ResourceResolver resourceResolver,
PageManagerFactory pageManagerFactory) {
//variantPath will have relations which should point to source language copies
adjustRelationsForAssetLanguageCopy(variantPath, relationName, targetLanguageCode,
resourceResolver);
Resource variantResource = resourceResolver.getResource(variantPath);
Resource updateAssetSourceResource = resourceResolver.getResource(updateAssetSourcePath);
List relatedAssets = getRelatedAssets(updateAssetSourceResource, relationName);
for (Asset relatedAsset : relatedAssets) {
String relatedAssetPath = relatedAsset.getPath();
if (relatedAssetPath.startsWith(DamConstants.MOUNTPOINT_ASSETS)) {
String tempLCOfRelatedAsset = createUpdateLanguageCopy(resourceResolver, pageManagerFactory,
relatedAssetPath, targetLanguageCode, prefixPath);
String LCofRelatedAsset = findLanguageCopyPathWithAutoCreatedRoots(relatedAssetPath,
targetLanguageCode, resourceResolver);
if (variantResource != null) {
com.adobe.granite.asset.api.Asset graniteVariantAsset = variantResource.adaptTo(com.adobe.granite
.asset.api.Asset.class);
if (graniteVariantAsset != null) {
adjustAssetRelations(graniteVariantAsset, relationName, LCofRelatedAsset, tempLCOfRelatedAsset);
// Remove the others relation for the variant language copy
removeAssetRelation(graniteVariantAsset, ATTRIBUTE_ASSET_OTHERS_RELATION);
} else {
log.warn("Resource not able to adaptTo com.adobe.granite.asset.api.Asset: "
+ variantResource.getPath());
}
} else {
log.warn("Resource not found in path: " + variantPath);
}
}
}
}
private static void adjustRelationsForAssetLanguageCopy(String assetPath, String relationName, String
targetLanguageCode, ResourceResolver resourceResolver) {
Resource assetResource = resourceResolver.resolve(assetPath);
if (null != assetResource) {
List relatedAssets = getRelatedAssets(assetResource, relationName);
for (Asset relatedAsset : relatedAssets) {
String relatedAssetPath = relatedAsset.getPath();
String sourceLanguageCode = getLanguageRootLocale(relatedAssetPath);
if (null == sourceLanguageCode || !sourceLanguageCode.equals(targetLanguageCode)) {
String languageCopyPath = findLanguageCopyPathWithAutoCreatedRoots(relatedAssetPath,
targetLanguageCode, resourceResolver);
com.adobe.granite.asset.api.Asset graniteAsset = assetResource.adaptTo(com.adobe.granite.asset
.api.Asset.class);
adjustAssetRelations(graniteAsset, relationName, relatedAssetPath, languageCopyPath);
}
}
}
}
public static String findLanguageCopyPathWithAutoCreatedRoots(final String assetPath,
final String languageCode, final ResourceResolver resolver) {
Asset languageCopy = findLanguageCopyWithAutoCreatedRoots(assetPath, languageCode, resolver);
return null != languageCopy ? languageCopy.getPath() : null;
}
public static Resource findLanguageCopyWithAutoCreatedRootsForAssetOrNTFolder(final Resource resource, final String
languageCode, final ResourceResolver resolver) throws RepositoryException {
if (null != resource.adaptTo(Asset.class)) {
Asset languageCopy = findLanguageCopyWithAutoCreatedRoots(resource.getPath(), languageCode, resolver);
if (null != languageCopy) {
return languageCopy.adaptTo(Resource.class);
}
} else if (isFolder(resource)) {
Node folderNode = findLanguageCopyForNTFolderWithAutoCreatedRoots(resource.getPath(), languageCode,
resolver);
if (null != folderNode) {
return resolver.getResource(folderNode.getPath());
}
}
return null;
}
public static Asset findLanguageCopyWithAutoCreatedRoots(final String assetPath, final String languageCode,
final ResourceResolver resolver) {
Resource assetResource = resolver.getResource(assetPath);
if (assetResource == null || assetResource.adaptTo(Asset.class) == null) {
return null;
}
Asset asset = null;
String languageRootPath = LanguageUtil.getLanguageRoot(assetPath);
String languageRootParentPath = null;
String contentPath = null;
if (languageRootPath != null) {
contentPath = assetPath.replaceFirst(languageRootPath, "");
languageRootParentPath = Text.getRelativeParent(
languageRootPath, 1);
} else {
//CQ-61450 User creates a language copy of a page from sites and language root for the asset (referenced in site) does not exist
if (Text.getRelativeParent(assetPath, 1).equals(DamConstants.MOUNTPOINT_ASSETS)) {
//Asset is directly under DamConstants.MOUNTPOINT_ASSETS
languageRootParentPath = DamConstants.MOUNTPOINT_ASSETS;
} else if (assetPath.startsWith(DamConstants.MOUNTPOINT_ASSETS + "/")) {
//Asset follows structure DamConstants.MOUNTPOINT_ASSETS//
int parentOfRootPathLength = assetPath.indexOf('/', DamConstants.MOUNTPOINT_ASSETS.length() + 1);
if (parentOfRootPathLength < 0 || assetPath.length() <= parentOfRootPathLength) {
return null;
}
languageRootParentPath = assetPath.substring(0, parentOfRootPathLength);
}
if (languageRootParentPath != null) {
contentPath = assetPath.replaceFirst(languageRootParentPath, "");
} else {
languageRootParentPath = "";
}
}
String destLanguageRootPath = getDestinationLanguageRoot(languageRootParentPath, languageCode, resolver);
String assetPathLC = destLanguageRootPath + contentPath;
Resource assetResourceLC = resolver.getResource(assetPathLC);
if (assetResourceLC != null) {
asset = assetResourceLC.adaptTo(Asset.class);
}
return asset;
}
private static Node findLanguageCopyForNTFolderWithAutoCreatedRoots(final String folderPath, final String
languageCode, final ResourceResolver resolver) throws RepositoryException {
Resource folderResource = resolver.getResource(folderPath);
if (folderResource == null) {
return null;
}
Node folderNode = folderResource.adaptTo(Node.class);
if (folderNode != null && !folderNode.isNodeType(JcrConstants.NT_FOLDER)) {
return null;
}
Node folderNodeLanguageCopy = null;
String languageRootPath = LanguageUtil.getLanguageRoot(folderPath);
String languageRootParentPath = null;
String contentPath = null;
if (languageRootPath != null) {
contentPath = folderPath.replaceFirst(languageRootPath, "");
languageRootParentPath = Text.getRelativeParent(
languageRootPath, 1);
} else {
//CQ-61450 User creates a language copy of a page from sites and language root for the asset (referenced in site) does not exist
if (Text.getRelativeParent(folderPath, 1).equals(DamConstants.MOUNTPOINT_ASSETS)) {
//Asset is directly under DamConstants.MOUNTPOINT_ASSETS
languageRootParentPath = DamConstants.MOUNTPOINT_ASSETS;
} else if (folderPath.startsWith(DamConstants.MOUNTPOINT_ASSETS + "/")) {
//Asset follows structure DamConstants.MOUNTPOINT_ASSETS//
int parentOfRootPathLength = folderPath.indexOf('/', DamConstants.MOUNTPOINT_ASSETS.length() + 1);
if (parentOfRootPathLength < 0 || folderPath.length() <= parentOfRootPathLength) {
return null;
}
languageRootParentPath = folderPath.substring(0, parentOfRootPathLength);
}
if (languageRootParentPath != null) {
contentPath = folderPath.replaceFirst(languageRootParentPath, "");
} else {
languageRootParentPath = "";
}
}
String destLanguageRootPath = getDestinationLanguageRoot(languageRootParentPath, languageCode, resolver);
String assetPathLC = destLanguageRootPath + contentPath;
Resource folderResourceLC = resolver.getResource(assetPathLC);
if (folderResourceLC != null) {
folderNodeLanguageCopy = folderResourceLC.adaptTo(Node.class);
}
return folderNodeLanguageCopy;
}
public static void afterReplacingUpdatedAsset(String destinationPath, Session userSession, String prefixPath,
ResourceResolver resourceResolver) throws RepositoryException {
Resource resource = resourceResolver.getResource(destinationPath);
if (null != resource) {
com.adobe.granite.asset.api.Asset graniteAsset = resource.adaptTo(com.adobe.granite.asset.api.Asset.class);
if (graniteAsset != null) {
afterReplacingUpdatedAssetWithRelation(ATTRIBUTE_ASSET_SOURCE_RELATION, graniteAsset, prefixPath);
afterReplacingUpdatedAssetWithRelation(ATTRIBUTE_ASSET_LINKS_RELATION, graniteAsset, prefixPath);
afterReplacingUpdatedAssetForSources(ATTRIBUTE_ASSET_LINKS_RELATION, graniteAsset, prefixPath);
}
}
userSession.save();
}
private static void afterReplacingUpdatedAssetForSources(String relationName,
com.adobe.granite.asset.api.Asset relaterAsset, String prefixPath) {
Resource relaterResource = relaterAsset.adaptTo(Resource.class);
List relatedSources = getRelatedAssets(relaterResource, ATTRIBUTE_ASSET_SOURCE_RELATION);
for (Asset relatedSource : relatedSources) {
com.adobe.granite.asset.api.Asset graniteSource = relatedSource
.adaptTo(com.adobe.granite.asset.api.Asset.class);
afterReplacingUpdatedAssetWithRelation(relationName, graniteSource, prefixPath);
}
}
private static void afterReplacingUpdatedAssetWithRelation(String relationName,
com.adobe.granite.asset.api.Asset graniteAsset, String prefixPath) {
List relations = getRelationsPathList(graniteAsset, relationName);
for (String relation : relations) {
String replacedRelationPath = removePrefix(relation, prefixPath);
if (null != replacedRelationPath) {
adjustAssetRelations(graniteAsset, relationName, relation, replacedRelationPath);
}
}
}
private static String removePrefix(String string, String prefix) {
return string.startsWith(prefix) ? string.replaceFirst(prefix, "") : null;
}
/**
* Returns the locale for the given path. Supports language root structures
* /<root>/\<path>lt;Language>_\<Country> and /\<root>lt;path>lt;Language>
* @param path
* @return locale or null in case any supported locale does not exist in the given path
*/
public static String getLanguageRootLocale(String path) {
String languageRootPath = LanguageUtil.getLanguageRoot(path);
if (null != languageRootPath) {
return languageRootPath.substring(languageRootPath.lastIndexOf("/") + 1);
}
return null;
}
public static String getLanguageDisplayName(ResourceResolver resolver, String langCode) {
String langDisplayName = "";
Resource languagesHome = resolver.getResource(DEFAULT_LANGUAGES_HOME);
Resource language = getLanguage(languagesHome, langCode);
if (language != null) {
ValueMap langProperties = language.adaptTo(ValueMap.class);
if (langProperties != null) {
langDisplayName = langProperties.get("language", String.class);
}
}
return (langDisplayName != null && !langDisplayName.isEmpty()) ? langDisplayName : langCode;
}
private static Resource getLanguage(Resource languagesHome, String languageCode) {
if (languagesHome != null) {
languageCode = languageCode.toLowerCase();
String langWithUnderscore = languageCode.replace("-", "_");
String langWithHyphen = languageCode.replace("_", "-");
Resource languageRes = languagesHome.getChild(langWithUnderscore);
if (languageRes == null) {
languageRes = languagesHome.getChild(langWithHyphen);
}
return languageRes;
}
return null;
}
/**
* Returns a list after replacing paths with their existing language copies. If a language copy of a path does
* not exist, the path is retained in the returned list.
*
* @param paths The list of paths whose language copy has to be replaced
* @param destinationLanguageCode language code of destination language copy
* @param resourceResolver
* @return a list after replacing paths with their existing language copies.
*/
public static List replaceWithExistingLanguageCopiesIfPossible(List paths,
String destinationLanguageCode, ResourceResolver resourceResolver) {
ArrayList resolveLanguageCopies = new ArrayList();
if (null == destinationLanguageCode) {
return paths;
}
for (String path : paths) {
String languageCopyPath = DamLanguageUtil.findLanguageCopyPathWithAutoCreatedRoots(path,
destinationLanguageCode, resourceResolver);
if (null != languageCopyPath) {
path = languageCopyPath;
}
resolveLanguageCopies.add(path);
}
return resolveLanguageCopies;
}
private static ArrayList getContentFragmentAssociatedAssets(Node currentNode, ResourceResolver
resourceResolver) throws RepositoryException {
Resource associatedContentResource = getAssociatedContentResource(currentNode.getPath(), resourceResolver);
if (associatedContentResource != null) {
ResourceCollection associatedContent = associatedContentResource.adaptTo(ResourceCollection.class);
return getAssetsFromAssociatedContentNode(associatedContent);
}
return new ArrayList();
}
public static ArrayList getAssetsFromAssociatedContent(Node contentFragmentNode, String destinationLanguage,
ResourceResolver resourceResolver) throws RepositoryException {
ArrayList returnList = new ArrayList();
Node associatedContentNode = getAssociatedContentNode(contentFragmentNode);
if (null != associatedContentNode) {
Resource associatedContentResource = resourceResolver.getResource(associatedContentNode.getPath());
if (associatedContentResource != null) {
Iterator collectionResourceIterator = getResourcesFromCollection(associatedContentResource);
if (collectionResourceIterator != null) {
//iterate over all collections
while (collectionResourceIterator.hasNext()) {
Resource collectionResource = collectionResourceIterator.next();
//check for collection
ResourceCollection damCollection = collectionResource.adaptTo(ResourceCollection.class);
if (damCollection != null) {
//get destination asset list
ArrayList collectionAssets = new ArrayList();
addAssetsFromCollection(damCollection, collectionAssets);
addAssetsFromNestedCollections(collectionResource, collectionAssets);
ArrayList sourceCollectionAssetLanguageCopies = getAssetLanguageCopiesFromSourceOfCollection(
collectionResource, destinationLanguage, resourceResolver);
if (null != sourceCollectionAssetLanguageCopies) {
//remove asset not present in source language copy of collection
removeLanguageCopiesWithoutSource(collectionAssets, sourceCollectionAssetLanguageCopies);
}
returnList.addAll(collectionAssets);
}
}
}
} else {
log.warn("Resource not found in path: " + associatedContentNode.getPath());
}
}
return returnList;
}
private static void addAssetsFromNestedCollections(Resource collectionResource, ArrayList collectionAssets)
throws RepositoryException {
//nested collection
HashSet nestedCollections = new HashSet();
getNestedCollections(collectionResource, nestedCollections);
for (Resource resource : nestedCollections) {
ResourceCollection rc = resource.adaptTo(ResourceCollection.class);
if (rc != null) {
addAssetsFromCollection(rc, collectionAssets);
} else {
log.warn("Resource is not adaptable to ResourceCollection object: " + resource.getPath());
}
}
}
private static Node getAssociatedContentNode(Node currentNode) throws RepositoryException {
if(currentNode.hasNode(ASSOCIATED_CONTENT_RELATIVE_PATH)) {
return currentNode.getNode(ASSOCIATED_CONTENT_RELATIVE_PATH);
}
if(currentNode.hasNode(ASSOCIATED_CONTENT_CHILD)) {
return currentNode.getNode(ASSOCIATED_CONTENT_CHILD);
}
return null;
}
private static Resource getAssociatedContentResource(String cfPath, ResourceResolver resourceResolver) throws
RepositoryException {
Resource resource = resourceResolver.getResource(cfPath + "/" + ASSOCIATED_CONTENT_RELATIVE_PATH);
if (null == resource) {
resource = resourceResolver.getResource(cfPath + "/" + ASSOCIATED_CONTENT_CHILD);
}
return resource;
}
private static void removeLanguageCopiesWithoutSource(ArrayList collectionAssets, ArrayList
sourceCollectionLanguageCopyPaths) {
if (null != sourceCollectionLanguageCopyPaths) {
for (int ndx = collectionAssets.size() - 1; ndx >= 0; ndx--) {
Asset collectionAsset = collectionAssets.get(ndx);
if (!sourceCollectionLanguageCopyPaths.contains(collectionAsset.getPath())) {
collectionAssets.remove(ndx);
}
}
}
}
private static ArrayList getAssetLanguageCopiesFromSourceOfCollection(Resource collectionResource, String
destinationLanguage, ResourceResolver resourceResolver) throws RepositoryException {
ArrayList sourceAssetList = getAssetsFromSourceOfCollection(collectionResource, resourceResolver);
if (null != sourceAssetList) {
ArrayList destinationCollectionAssets = new ArrayList();
for (Asset asset : sourceAssetList) {
Asset languageCopy = DamLanguageUtil.findLanguageCopyWithAutoCreatedRoots(asset.getPath(),
destinationLanguage, resourceResolver);
if (null != languageCopy) {
destinationCollectionAssets.add(languageCopy.getPath());
}
}
return destinationCollectionAssets;
}
return null;
}
private static ArrayList getAssetsFromSourceOfCollection(Resource collectionResource,
ResourceResolver resourceResolver) throws RepositoryException {
Resource sourceCollection = getSourceCollection(collectionResource, resourceResolver);
if (null != sourceCollection) {
ArrayList sourceAssetList = getAssetsFromCollection(sourceCollection);
deleteProperty(collectionResource, ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY);
return sourceAssetList;
}
return null;
}
private static void deleteProperty(Resource collectionResource, String property) throws RepositoryException {
Node collectionNode = collectionResource.adaptTo(Node.class);
if (collectionNode != null && collectionNode.hasProperty(property)) {
javax.jcr.Property sourceCollectionProperty = collectionNode.getProperty(property);
sourceCollectionProperty.remove();
}
}
private static Resource getSourceCollection(Resource collectionResource, ResourceResolver resourceResolver)
throws RepositoryException {
Node collectionNode = collectionResource.adaptTo(Node.class);
if (collectionNode != null && collectionNode.hasProperty(ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY)) {
javax.jcr.Property sourceCollectionProperty = collectionNode.getProperty(
ATTRIBUTE_COLLECTION_SOURCE_LANGUAGE_COPY);
String sourceCollectionPath = sourceCollectionProperty.getString();
return resourceResolver.getResource(sourceCollectionPath);
}
return null;
}
private static ArrayList getAssetsFromCollection(Resource collectionResource)
throws RepositoryException {
ArrayList assetList = new ArrayList();
return addAssetsFromCollectionResource(collectionResource, assetList);
}
private static ArrayList getAssetsFromAssociatedContentNode(ResourceCollection resourceCollection) throws
RepositoryException {
ArrayList assetList = new ArrayList();
if (resourceCollection != null) {
Iterator resourceIterator = resourceCollection.getResources();
while (resourceIterator.hasNext()) {
Resource collectionResource = resourceIterator.next();
addAssetsFromCollectionResource(collectionResource, assetList);
}
}
return assetList;
}
private static ArrayList addAssetsFromCollectionResource(Resource collectionResource,
ArrayList assetList) throws RepositoryException {
if (null == collectionResource) {
return assetList;
}
ResourceCollection resourceCollection = collectionResource.adaptTo(ResourceCollection.class);
if (null == resourceCollection) {
return assetList;
}
addAssetsFromCollection(resourceCollection, assetList);
addAssetsFromNestedCollections(collectionResource, assetList);
return assetList;
}
private static void getNestedCollections(Resource sourceCollectionResource, HashSet updatedCollections)
throws RepositoryException {
ResourceCollection sourceCollection = sourceCollectionResource.adaptTo(ResourceCollection.class);
Iterator sourceResources = sourceCollection.getResources();
while (sourceResources.hasNext()) {
Resource sourceResource = sourceResources.next();
if (isDamCollection(sourceResource) && !updatedCollections.contains(sourceResource)) {
updatedCollections.add(sourceResource);
getNestedCollections(sourceResource, updatedCollections);
}
}
}
private static void addAssetsFromCollection(ResourceCollection resourceCollection, ArrayList assetList)
throws RepositoryException {
Iterator resourceIterator = resourceCollection.getResources();
while (resourceIterator.hasNext()) {
Resource resource = resourceIterator.next();
Asset asset = resource.adaptTo(Asset.class);
if (asset != null && !isContentFragment(asset)) {
assetList.add(asset);
} else if (isFolder(resource)) {
Iterator assetIterator = DamUtil.getAssets(resource);
while (assetIterator.hasNext()) {
Asset folderAsset = assetIterator.next();
if(!isContentFragment(folderAsset)) {
assetList.add(folderAsset);
}
}
}
}
}
private static boolean isTranslateAssociatedContent(Resource contentFragmentResource, ResourceResolver
resourceResolver) {
boolean retVal = false;
//get cloud config resource
Resource cloudConfigResource = getCloudConfigResourceAppliedOnResource(contentFragmentResource,
MachineTranslationCloudConfig.class, null, resourceResolver);
//check if translation is required
if (null != cloudConfigResource) {
MachineTranslationCloudConfig cloudConfig = cloudConfigResource.adaptTo(
MachineTranslationCloudConfig.class);
if (null != cloudConfig) {
retVal = cloudConfig.isTranslateAssociatedContentForAssets();
}
}
return retVal;
}
private static boolean isTranslateInlineMediaAssets(String contentFragmentPath, ResourceResolver
resourceResolver) {
boolean retVal = false;
Resource contentFragmentResource = resourceResolver.getResource(contentFragmentPath);
if (null != contentFragmentResource) {
//get cloud config resource
Resource cloudConfigResource = getCloudConfigResourceAppliedOnResource(contentFragmentResource,
MachineTranslationCloudConfig.class, null, resourceResolver);
//check if translation is required
if (null != cloudConfigResource) {
MachineTranslationCloudConfig cloudConfig = cloudConfigResource.adaptTo(
MachineTranslationCloudConfig.class);
if (null != cloudConfig) {
retVal = cloudConfig.isTranslateInlineMediaAssets();
}
}
}
return retVal;
}
private static boolean isTranslationOnUpdateOnlyDisabledForAssets(String assetPath, ResourceResolver
resourceResolver) {
boolean retVal = false;
Resource assetResource = resourceResolver.getResource(assetPath);
if (null != assetResource) {
//get cloud config resource
Resource cloudConfigResource = getCloudConfigResourceAppliedOnResource(assetResource,
MachineTranslationCloudConfig.class, null, resourceResolver);
if (null != cloudConfigResource) {
MachineTranslationCloudConfig cloudConfig = cloudConfigResource.adaptTo(
MachineTranslationCloudConfig.class);
if (null != cloudConfig) {
retVal = cloudConfig.isTranslationOnUpdateOnlyDisabledForAssets();
}
}
}
return retVal;
}
private static boolean isTargetPathInDraftState(Asset targetAsset) throws RepositoryException {
boolean retVal = false;
Resource targetAssetResource= targetAsset.adaptTo(Resource.class);
if (targetAssetResource != null) {
Resource contentResource = targetAssetResource.getChild(JcrConstants.JCR_CONTENT);
contentResource = contentResource == null ? targetAssetResource : contentResource;
Node contentNode = contentResource.adaptTo(Node.class);
if (contentNode != null) {
if (contentNode.hasProperty(ATTRIBUTE_CQ_TRANSLATION_STATUS)) {
Property property = contentNode.getProperty(ATTRIBUTE_CQ_TRANSLATION_STATUS);
if (property.getString().equals(TranslationConstants.TranslationStatus.DRAFT.toString())) {
retVal = true;
}
} else {
retVal = true;
}
} else {
log.warn("Content resource not adaptable to Node object: " + contentResource.getPath());
}
} else {
log.warn("Asset is not adaptable to Resource object: " + targetAsset.getPath());
}
return retVal;
}
private static ContentState getContentStateForSmartTranslation(Asset sourceAsset ,Asset targetAsset,
ResourceResolver resourceResolver) throws RepositoryException {
ContentState contentState = ContentState.IS_TRANSLATED;
boolean isSmartAssetUpdate = false;
boolean isTranslationOnUpdateOnly = false;
if (isSmartAssetUpdateRequired(sourceAsset, targetAsset)) {
isSmartAssetUpdate = true;
}
if (isTranslationOnUpdateOnlyDisabledForAssets(targetAsset.getPath(), resourceResolver)) {
isTranslationOnUpdateOnly = true;
}
Resource targetAssetResource= targetAsset.adaptTo(Resource.class);
if (targetAssetResource != null) {
Resource contentResource = targetAssetResource.getChild(JcrConstants.JCR_CONTENT);
contentResource = contentResource == null ? targetAssetResource : contentResource;
Node contentNode = contentResource.adaptTo(Node.class);
if (contentNode != null) {
if (contentNode.hasProperty(ATTRIBUTE_CQ_TRANSLATION_STATUS)) {
Property property = contentNode.getProperty(ATTRIBUTE_CQ_TRANSLATION_STATUS);
if (property.getString().equals(TranslationConstants.TranslationStatus.DRAFT.toString()) ||
isSmartAssetUpdate || isTranslationOnUpdateOnly) {
contentState = ContentState.IS_UPDATE_STATE;
}
} else if (contentNode.hasProperty(ATTRIBUTE_CQ_TRANSLATION_LAST_UPDATE)) {
if (isSmartAssetUpdate) {
contentState = ContentState.IS_UPDATE_STATE;
} else if (!contentNode.hasProperty(CQ_TRANSLATION_SOURCE_JCR_UUID)) {
Node sourceAssetNode = sourceAsset.adaptTo(Node.class);
if ((sourceAssetNode != null && !sourceAssetNode.hasProperty(JCR_UUID)) || isTranslationOnUpdateOnly) {
contentState = ContentState.IS_UPDATE_STATE;
} else {
contentState = ContentState.IS_UNKNOWN;
log.error("Content resource language copy creation is in unknown state thus, skipped from processing: "
+ contentResource.getPath());
}
} else {
contentState = ContentState.IS_CREATE_STATE;
}
} else {
log.warn("Content resource language copy is migrated content without any translation properties: "
+ contentResource.getPath());
contentState = ContentState.IS_UPDATE_STATE;
}
} else {
log.warn("Content resource not adaptable to Node object: " + contentResource.getPath());
}
} else {
log.warn("Asset is not adaptable to Resource object: " + targetAsset.getPath());
}
return contentState;
}
private static Resource getContentResource(Resource resource) {
if(resource != null) {
boolean isContentNode = resource.getPath().equals(JcrConstants.JCR_CONTENT);
Resource content;
if (!isContentNode) {
content = resource.getChild(JcrConstants.JCR_CONTENT);
} else {
content = resource;
}
return content;
}
return null;
}
private static Resource getCloudConfigResourceAppliedOnResource(Resource resource,
Class> cloudConfigClass, String strCloudConfigResourceType, ResourceResolver resourceResolver) {
String cloudConfigPath = getCloudConfigPathAppliedOnResourceFromClassOrResourceType(resource, cloudConfigClass,
strCloudConfigResourceType, resourceResolver);
if (null != cloudConfigPath) {
return resourceResolver.getResource(cloudConfigPath);
}
return null;
}
/**
* Returns the path of cloud config applied on or inherited by a resource.
*/
private static String getCloudConfigPathAppliedOnResourceFromClassOrResourceType(Resource resource,
Class> cloudConfigClass, String strCloudConfigResourceType, ResourceResolver resourceResolver) {
if (resource == null || (cloudConfigClass == null && strCloudConfigResourceType == null)) {
return null;
}
log.debug("In Function: getCloudConfigAppliedOnResource({})", resource.getPath());
String strCloudConfigPath = null;
String[] appliedCloudConfigs = null;
if (resourceResolver != null) {
Resource content = getContentResource(resource);
if (content != null) {
if (log.isDebugEnabled()) {
log.debug("Resource: {}", resource.getPath());
log.debug("Content: {}", content.getPath());
}
boolean isContextAwareConfig = false;
if (ResourceUtil.getValueMap(content).get(ATTRIBUTE_CA_CONFIG_PROPERTY) != null) {
isContextAwareConfig = true;
}
// First look for context aware cloud configurations
if (isContextAwareConfig) {
try {
appliedCloudConfigs = getCAConfigs(resource);
} catch (Exception e) {
log.error("Failed to get configs.", e);
}
}
// if no configurations found, look for legacy cloud configurations
if (appliedCloudConfigs == null || appliedCloudConfigs.length == 0) {
try {
appliedCloudConfigs = (String[]) ResourceUtil.getValueMap(content).get(
ATTRIBUTE_CLOUD_CONFIG_PROPERTY);
} catch (ClassCastException cce) {
log.debug("Trying to cast as String as String[] failed");
String singleValue = (String) ResourceUtil.getValueMap(content).get(
ATTRIBUTE_CLOUD_CONFIG_PROPERTY);
if (singleValue != null && !"".equals(singleValue)) {
appliedCloudConfigs = new String[1];
appliedCloudConfigs[0] = singleValue;
}
}
}
if (appliedCloudConfigs != null) {
for (String appliedCloudConfig : appliedCloudConfigs) {
Resource appliedConfig = resourceResolver.getResource(appliedCloudConfig);
if (cloudConfigClass != null) {
if (appliedConfig != null && appliedConfig.adaptTo(cloudConfigClass) != null) {
strCloudConfigPath = appliedCloudConfig;
log.debug("Found ObjectCloudConfig {}", strCloudConfigPath);
return strCloudConfigPath;
} else {
log.debug("Applied Cloud Config {} is not of type {}.", appliedCloudConfig,
cloudConfigClass.toString());
}
} else {
Resource appliedConfigContent = getContentResource(appliedConfig);
if (appliedConfigContent != null) {
String strCurrentResourceType = appliedConfigContent.getResourceType();
if (strCloudConfigResourceType.equals(strCurrentResourceType)) {
strCloudConfigPath = appliedCloudConfig;
log.debug("Found ObjectCloudConfig {}", strCloudConfigPath);
return strCloudConfigPath;
} else {
log.debug("Applied Cloud Config {} is not of type {}.", appliedCloudConfig,
strCloudConfigResourceType);
}
}
}
}
}
}
//getCloudConfigPathApplied on parent resource
strCloudConfigPath = getCloudConfigPathAppliedOnResourceFromClassOrResourceType(resource.getParent(),
cloudConfigClass, strCloudConfigResourceType, resourceResolver);
} else {
log.warn("Failed to get resourceResolver");
}
return strCloudConfigPath;
}
private static String[] getCAConfigs(Resource resource) throws Exception {
ArrayList caConfigs = new ArrayList();
Conf conf = resource.adaptTo(Conf.class);
if (conf != null) {
// get TIF config
Collection tifCollection = conf.getListResources(CACONFIG_TRANSLATIONCFG_PATH);
if (null == tifCollection) {
return new String[0];
}
Resource tif = getConfigFromCollection(tifCollection);
if (tif != null) {
caConfigs.add(tif.getPath());
}
}
String[] caConfigsArray = new String[caConfigs.size()];
return caConfigs.toArray(caConfigsArray);
}
private static Resource getConfigFromCollection(Collection tifCollection) {
Iterator tifIterator = tifCollection.iterator();
ArrayList tifList = new ArrayList();
while (tifIterator.hasNext()) {
tifList.add(tifIterator.next());
}
if (tifList.size() == 1) {
return tifList.get(0);
} else if (tifList.size() > 1) {
// custom configuration
for (int ndx = 0; ndx < tifList.size(); ndx++) {
Resource currTif = tifList.get(ndx);
if (currTif.getPath().startsWith(CACONFIG_ROOT) && !currTif.getPath().startsWith(CACONFIG_GLOBAL)) {
return currTif;
}
}
String[] fallbackPaths = {CACONFIG_GLOBAL, "/apps"};
// fallback from /conf/global, then apps
// case of /libs taken care of in tifList.size() == 1
for (String fallbackPath : fallbackPaths) {
for (int ndx = 0; ndx < tifList.size(); ndx++) {
Resource currTif = tifList.get(ndx);
if (currTif.getPath().startsWith(fallbackPath)) {
return currTif;
}
}
}
}
return null;
}
private static void setLastTranslationUpdate(Resource resource) throws RepositoryException {
if (resource != null) {
Resource contentResource = resource.getChild(JcrConstants.JCR_CONTENT);
if (contentResource != null) {
Node sourceContentNode = contentResource.adaptTo(Node.class);
Calendar lastModified = getNodeLastModifiedTime(contentResource);
if (lastModified == null) {
lastModified = Calendar.getInstance();
}
if(sourceContentNode != null){
sourceContentNode.setProperty(ATTRIBUTE_CQ_TRANSLATION_LAST_UPDATE, lastModified);
}
}
}
}
private static void setIsTranslationCreated(Resource resource) throws RepositoryException {
if (resource != null) {
Resource contentResource = resource.getChild(JcrConstants.JCR_CONTENT);
if (contentResource != null) {
Node contentNode = contentResource.adaptTo(Node.class);
if(contentNode != null) {
contentNode.setProperty(ATTRIBUTE_CQ_TRANSLATION_CREATED, true);
}
}
}
}
private static void setTransCreatedFlagToPathResource (String transCreatedPath, String pathAlreadyPresent, ResourceResolver resourceResolver)
throws RepositoryException {
Session session = resourceResolver.adaptTo(Session.class);
while(transCreatedPath.length()>0) {
String completePath = pathAlreadyPresent + transCreatedPath;
Node tempNode = null;
if (session.itemExists(completePath)) {
tempNode = session.getNode(completePath);
}
if (tempNode != null){
setIsTranslationCreated(resourceResolver.getResource(tempNode.getPath()));
}
transCreatedPath = transCreatedPath.substring(0,transCreatedPath.lastIndexOf("/"));
}
}
private static String getTransCreatedPath(String pathToCheck, Session session) throws RepositoryException {
String[] elements = Text.explode(pathToCheck, '/');
Node dstParent = session.getNode(DamConstants.MOUNTPOINT_ASSETS);
String transCreatedPath = "";
for (int j = 0; j < elements.length; j++) {
String name = elements[j];
if (!dstParent.hasNode(name)) {
transCreatedPath = transCreatedPath + "/" + name;
break;
} else {
dstParent = dstParent.getNode(name);
}
}
transCreatedPath = transCreatedPath == "" ? "" : transCreatedPath + "/" ;
if(transCreatedPath!="") {
transCreatedPath = pathToCheck.substring(pathToCheck.indexOf(transCreatedPath));
}
return transCreatedPath;
}
private static Calendar getNodeLastModifiedTime(Resource contentNode) {
Calendar retVal = null;
Calendar cqLastModified = getCalendarAttribute(contentNode, CQ_LASTMODIFIED);
Calendar jcrLastModified = getCalendarAttribute(contentNode, JCR_LASTMODIFIED);
if (cqLastModified != null && jcrLastModified != null) {
if (cqLastModified.compareTo(jcrLastModified) > 0) {
retVal = cqLastModified;
} else {
retVal = jcrLastModified;
}
} else if (jcrLastModified != null) {
retVal = jcrLastModified;
} else if (cqLastModified != null) {
retVal = cqLastModified;
}
return retVal;
}
private static Calendar getCalendarAttribute(Resource resource, String strAttributeName) {
ValueMap contentVM = resource.adaptTo(ValueMap.class);
if (contentVM == null) {
return null;
} else {
return contentVM.get(strAttributeName, Calendar.class);
}
}
/**
* Returns the destination language root for the given path by analyzing the path names starting at the root.
*
* @param srcLanguageRootParentPath source language root's parent path
* @return the destination language root or null
if not found
*/
private static String getDestinationLanguageRoot(@Nonnull String srcLanguageRootParentPath, @Nonnull String
destinationLanguage, @Nonnull ResourceResolver resourceResolver) {
Resource langRootParent = resourceResolver.getResource(srcLanguageRootParentPath);
if (null != langRootParent) {
//language root based on path
destinationLanguage = getDestinationLanguageWithAllowedDelimiters(srcLanguageRootParentPath,
destinationLanguage, resourceResolver);
String sameLevelDestinationRootPath = srcLanguageRootParentPath + "/" + destinationLanguage;
if (null != resourceResolver.getResource(sameLevelDestinationRootPath)) {
return sameLevelDestinationRootPath;
}
/**
* Check for Language roots at two level
*/
//go one level down
Iterator iter = langRootParent.listChildren();
while (iter.hasNext()) {
Resource sibling = iter.next();
Locale locale = getLocaleFromResource(sibling);
if (locale == null) {
String retVal = checkAndGetLanguageRootsFromChildren(sibling, destinationLanguage);
if (null != retVal) {
return retVal;
}
}
}
//one level up
//find language roots which are not language countries
Resource langRootGrandParent = langRootParent.getParent();
ArrayList nonLangRootUncles = new ArrayList();
boolean additionalLanguageRootsFound = false;
if (langRootGrandParent != null) {
Iterator langRootUncles = langRootGrandParent.listChildren();
while (langRootUncles.hasNext()) {
Resource langRootUncle = langRootUncles.next();
if (langRootUncle.getName().equals(langRootParent.getName())) { //node comparison not working :(
//already checked
continue;
}
Locale gcLocale = getLocaleFromResource(langRootUncle);
//check that this is not a country node and locale is same
if (!isCountryNode(langRootUncle)) {
additionalLanguageRootsFound = true;
if (null != gcLocale) {
String gcLanguage = gcLocale.getLanguage().toString();
if (destinationLanguage.equals(gcLanguage)) {
return langRootUncle.getPath();
}
} else {
nonLangRootUncles.add(langRootUncle);
}
}
}
}
if (additionalLanguageRootsFound) {
//found roots one level up, need to go down on nonLangRootUncles.
for (Resource nonLangRootUncle : nonLangRootUncles) {
String retVal = checkAndGetLanguageRootsFromChildren(nonLangRootUncle,
destinationLanguage);
if (null != retVal) {
return retVal;
}
}
}
//fallback to language root based on path
return sameLevelDestinationRootPath;
}
return null;
}
private static String checkAndGetLanguageRootsFromChildren(Resource resource, String destLanguage) {
Iterator children = resource.listChildren();
while (children.hasNext()) {
Resource child = children.next();
Locale childLocale = getLocaleFromResource(child);
if (childLocale != null) {
String childLanguage = childLocale.getLanguage().toString();
if(childLanguage.equals(destLanguage)) {
return child.getPath();
}
}
}
return null;
}
private static Locale getLocaleFromResource(@Nonnull Resource res) {
Language language = LanguageUtil.getLanguage(res.getName());
if (language != null) {
return language.getLocale();
}
return null;
}
private static boolean isCountryNode(Resource resource) {
Iterator children = resource.listChildren();
while (children.hasNext()) {
Resource child = children.next();
Locale gcLocale = getLocaleFromResource(child);
if (gcLocale != null) {
return true;
}
}
return false;
}
public static ResourceResolver getUserResourceResolverFromUserId(SlingRepository slingRepository, ResourceResolverFactory resolverFactory, String userId, String serviceUser )
throws LoginException, RepositoryException {
Session initiatorSession = getUserSession(slingRepository, userId, serviceUser);
return resolverFactory.getResourceResolver(Collections.singletonMap(org.apache.sling.jcr.resource.JcrResourceConstants.AUTHENTICATION_INFO_SESSION, (Object) initiatorSession));
}
private static Session getUserSession(SlingRepository slingRepository, String userId, String serviceUser) throws RepositoryException {
final SimpleCredentials credentials = new SimpleCredentials(userId, new char[0]);
Session session = slingRepository.impersonateFromService(serviceUser, credentials, null);
try {
session.getWorkspace().getObservationManager().setUserData(CHANGE_BY_TRANSLATION_WORKFLOW);
} catch (NullPointerException | RepositoryException e) {
log.error("Error while setting user data on session", e);
}
return session;
}
/**
* This code should maintain parity with {@code com.adobe.cq.wcm.translation.impl.utils.CFEmbeddedAssetUtil}
* Any changes made here should also be reflected in the other class as well
*/
private static class CFEmbeddedAssetUtil {
private static final Logger logger = LoggerFactory.getLogger(CFEmbeddedAssetUtil.class);
/**
* Returns inline media assets and referenced assets/CFs, together called embedded assets,
* which are present inside a content Fragment.
*
* Use same value of isRecursive Parameter for single workflow execution. Mix and match of true and false
* could result in unwanted results.
*
* @param contentFragmentNodePath Path Of CF for which user needs to get embeddedAssets/referenced Content Fragments
* @param resourceResolver ResourceResolver instance
* @param isRecursive true if user wants to getEmbeddedAssets recursively.
* @return embedded assets
*/
public static Set getEmbeddedAssets(String contentFragmentNodePath, ResourceResolver resourceResolver, boolean isRecursive)
throws RepositoryException, IOException {
logger.debug("In Function: getEmbeddedAssets");
Resource cfResource = resourceResolver.getResource(contentFragmentNodePath);
if (cfResource == null) {
logger.info("Resource not found at path: {}", contentFragmentNodePath);
return Collections.emptySet();
}
ContentFragment cf = cfResource.adaptTo(ContentFragment.class);
if (cf == null) {
logger.info("Content Fragment not found at path: {}", contentFragmentNodePath);
return Collections.emptySet();
}
HashSet embeddedAssets = new HashSet<>();
HashSet processedCFs = new HashSet<>();
processedCFs.add(contentFragmentNodePath);
embeddedAssets.addAll(getEmbeddedAssetsForCFRecursive(contentFragmentNodePath, resourceResolver, processedCFs, isRecursive));
return embeddedAssets;
}
/**
*
* Replaces embedded assets and referenced assets/CFs which are present inside a content Fragment
* with their destination language copies.
*
* Use same value of isRecursive Parameter for single workflow execution. Mix and match of true and false
* could result in unwanted results.
*
*
* @param currentNode Node in which user needs to replace embeddedAssetsReferences
* @param destinationLanguage the target language code
* @param resourceResolver ResourceResolver instance
* @param isRecursive true if user wants to replace EmbeddedAssets recursively
*/
public static void updateEmbeddedAssetReferences(Node currentNode, String destinationLanguage,
ResourceResolver resourceResolver, boolean isRecursive) throws RepositoryException, ContentFragmentException {
replaceEmbeddedAssets(currentNode.getPath(), destinationLanguage, resourceResolver, isRecursive);
}
private static Set getEmbeddedAssetsForCFRecursive(String contentFragmentNodePath,
ResourceResolver resourceResolver, HashSet processedCFs, boolean isRecursive)
throws RepositoryException, IOException {
logger.debug("In Function: getEmbeddedAssetsForCFRecursive");
HashSet embeddedAssets = new HashSet<>();
Resource cfResource = resourceResolver.getResource(contentFragmentNodePath);
if (cfResource == null) {
logger.info("Resource not found at path: {}", contentFragmentNodePath);
return Collections.emptySet();
}
ContentFragment cf = cfResource.adaptTo(ContentFragment.class);
if (cf == null) {
logger.info("Content Fragment not found at path: {}",
contentFragmentNodePath);
return Collections.emptySet();
}
Iterator cfElements = cf.getElements();
while (cfElements.hasNext()) {
ContentElement currentElement = cfElements.next();
embeddedAssets.addAll(getEmbeddedAssetsForCFElementAndItsReferences(cf, currentElement, resourceResolver,
processedCFs, isRecursive));
}
return embeddedAssets;
}
private static HashSet getEmbeddedAssetsForCFElementAndItsReferences(ContentFragment contentFragment,
ContentElement contentElement, ResourceResolver resourceResolver, HashSet processedCFs, boolean isRecursive)
throws IOException, RepositoryException {
logger.debug("In Function: getEmbeddedAssetsForCFElementAndItsReferences");
HashSet embeddedAssets = new HashSet();
HashSet assetPaths = getEmbeddedAssetPaths(contentElement);
for (String assetPath : assetPaths) {
Resource resource = resourceResolver.getResource(decodeURL(assetPath));
if (null != resource) {
Asset asset = resource.adaptTo(Asset.class);
if (null != asset) {
Node resourceNode = resource.adaptTo(Node.class);
if (resourceNode != null && isContentFragment(resourceNode)) {
if (processedCFs.contains(assetPath)) {
continue;
} else {
processedCFs.add(assetPath);
if (isRecursive) {
embeddedAssets.addAll(
getEmbeddedAssetsForCFRecursive(assetPath, resourceResolver, processedCFs, isRecursive));
} else {
embeddedAssets.add(asset);
}
}
}
embeddedAssets.add(asset);
}
}
}
return embeddedAssets;
}
private static HashSet getEmbeddedAssetPaths(ContentElement contentElement) {
logger.debug("In Function: getEmbeddedAssetPaths");
HashSet assets = new HashSet<>();
if (isElementFragmentOrContentReference(contentElement)) {
assets.addAll(Arrays.asList(CFEmbeddedAssetUtil.ContentFragmentValueWrapper
.getValue(contentElement)));
Iterator elementVariations = contentElement.getVariations();
while (elementVariations.hasNext()) {
ContentVariation currentVariation = elementVariations.next();
assets.addAll(Arrays.asList(ContentFragmentValueWrapper
.getValue(currentVariation)));
}
return assets;
} else {
assets.addAll(getEmbeddedInlineMediaAssets(contentElement.getContent()));
Iterator elementVariations = contentElement.getVariations();
while (elementVariations.hasNext()) {
ContentVariation currentVariation = elementVariations.next();
assets.addAll(getEmbeddedInlineMediaAssets(currentVariation.getContent()));
}
return assets;
}
}
private static void replaceEmbeddedAssets(String contentFragmentNodePath, String targetLanguageCode,
ResourceResolver resourceResolver, boolean isRecursive) throws ContentFragmentException {
logger.debug("In Function: replaceEmbeddedAssets");
Resource cfResource = resourceResolver.getResource(contentFragmentNodePath);
if (cfResource == null) {
logger.info("Resource not found at path: {}", contentFragmentNodePath);
return;
}
ContentFragment cf = cfResource.adaptTo(ContentFragment.class);
if (cf == null) {
logger.info("Content Fragment not found at path: {}", contentFragmentNodePath);
return;
}
HashSet processedAssets = new HashSet<>();
processedAssets.add(contentFragmentNodePath);
replaceEmbeddedAssetsRecursive(contentFragmentNodePath, targetLanguageCode, resourceResolver,
processedAssets, isRecursive);
}
private static class ContentFragmentValueWrapper {
private static String[] getValue(ContentElement element) {
String[] values = element.getValue().getValue(String[].class);
return (null == values || (values.length == 1 && null == values[0])) ? new String[]{} : values;
}
private static String[] getValue(ContentVariation variation) {
String[] values = variation.getValue().getValue(String[].class);
return (null == values || (values.length == 1 && null == values[0])) ? new String[]{} : values;
}
private static void setValue(ContentElement element, String[] content) throws ContentFragmentException {
FragmentData fragmentData = element.getValue();
updateFragmentData(fragmentData, content);
element.setValue(fragmentData);
}
private static void setValue(ContentVariation variation, String[] content) throws ContentFragmentException {
FragmentData fragmentData = variation.getValue();
updateFragmentData(fragmentData, content);
variation.setValue(fragmentData);
}
private static void updateFragmentData(FragmentData fragmentData, String[] content)
throws ContentFragmentException {
if (fragmentData.getDataType().isMultiValue()) {
fragmentData.setValue(content);
} else {
fragmentData.setValue(content[0]);
}
}
}
private static void replaceEmbeddedAssetsRecursive(String contentFragmentNodePath, String targetLanguageCode,
ResourceResolver resourceResolver, HashSet processedCFs, boolean isRecursive) throws ContentFragmentException {
logger.debug("In Function: replaceEmbeddedAssetsRecursion");
Resource cfResource = resourceResolver.getResource(contentFragmentNodePath);
if (cfResource == null) {
logger.info("Resource not found at path: {}", contentFragmentNodePath);
return;
}
ContentFragment cf = cfResource.adaptTo(ContentFragment.class);
if (cf == null) {
logger.info("Content Fragment not found at path: {}", contentFragmentNodePath);
return;
}
Iterator cfElemnemts = cf.getElements();
while (cfElemnemts.hasNext()) {
ContentElement currentElement = cfElemnemts.next();
if (isElementFragmentOrContentReference(currentElement)) {
String[] elementValues = ContentFragmentValueWrapper.getValue(currentElement);
boolean bElementValuesUpdated = false;
for (int ndx = 0; ndx < elementValues.length; ndx++) {
if (hasLanguageRoot(elementValues[ndx])) {
boolean isURLEncoded = isURLEncoded(elementValues[ndx]);
String languageCopyPath = getLanguageCopyForEncodedURL(elementValues[ndx],
targetLanguageCode, resourceResolver);
if (languageCopyPath != null) {
elementValues[ndx] = isURLEncoded ? encodeURL(languageCopyPath) : languageCopyPath;
bElementValuesUpdated = true;
if (!processedCFs.contains(languageCopyPath)) {
Resource languageCopyResource = resourceResolver.getResource(languageCopyPath);
if (languageCopyResource == null) {
logger.warn("Content Reference not found at path: {}. " +
"This Content Reference cannot be processed further for embedded assets.", languageCopyPath);
} else {
Node node = languageCopyResource.adaptTo(Node.class);
if (node != null && isContentFragment(node)) {
processedCFs.add(languageCopyPath);
if (isRecursive) {
replaceEmbeddedAssetsRecursive(languageCopyPath, targetLanguageCode,
resourceResolver, processedCFs, isRecursive);
}
}
}
}
}
}
}
if (bElementValuesUpdated) {
CFEmbeddedAssetUtil.ContentFragmentValueWrapper.setValue(currentElement, elementValues);
}
Iterator elementVariations = currentElement.getVariations();
while (elementVariations.hasNext()) {
ContentVariation currentVariation = elementVariations.next();
String[] variationValues = CFEmbeddedAssetUtil.ContentFragmentValueWrapper.getValue(currentVariation);
boolean bVariationValuesUpdated = false;
for (int ndx = 0; ndx < variationValues.length; ndx++) {
if (hasLanguageRoot(variationValues[ndx])) {
boolean isURLEncoded = isURLEncoded(elementValues[ndx]);
String languageCopyPath = getLanguageCopyForEncodedURL(variationValues[ndx],
targetLanguageCode, resourceResolver);
if (languageCopyPath != null) {
variationValues[ndx] = isURLEncoded ? encodeURL(languageCopyPath) : languageCopyPath;
bVariationValuesUpdated = true;
if (!processedCFs.contains(languageCopyPath)) {
Resource languageCopyResource = resourceResolver.getResource(languageCopyPath);
if (languageCopyResource == null) {
logger.warn("Content Reference not found at path: {}. " +
"This Content Reference cannot be processed further for embedded assets.", languageCopyPath);
} else {
Node node = languageCopyResource.adaptTo(Node.class);
if (node != null && isContentFragment(node)) {
processedCFs.add(languageCopyPath);
if (isRecursive) {
replaceEmbeddedAssetsRecursive(languageCopyPath, targetLanguageCode,
resourceResolver, processedCFs, isRecursive);
}
}
}
}
}
}
}
if (bVariationValuesUpdated) {
ContentFragmentValueWrapper.setValue(currentVariation, variationValues);
}
}
} else {
String[] elementValues = CFEmbeddedAssetUtil.ContentFragmentValueWrapper
.getValue(currentElement);
boolean bElementValuesUpdated = false;
for (int ndx = 0; ndx < elementValues.length; ndx++) {
if (StringUtils.isNotBlank(elementValues[ndx])) {
elementValues[ndx] = replaceEmbeddedInlineMediaAssetsInVariationData(elementValues[ndx],
targetLanguageCode, resourceResolver);
bElementValuesUpdated = true;
}
}
if (bElementValuesUpdated) {
CFEmbeddedAssetUtil.ContentFragmentValueWrapper.setValue(currentElement, elementValues);
}
Iterator elementVariations = currentElement.getVariations();
while (elementVariations.hasNext()) {
ContentVariation currentVariation = elementVariations.next();
String[] variationValues = CFEmbeddedAssetUtil.ContentFragmentValueWrapper
.getValue(currentVariation);
boolean bVariationValuesUpdated = false;
for (int ndx = 0; ndx < variationValues.length; ndx++) {
if (StringUtils.isNotBlank(variationValues[ndx])) {
variationValues[ndx] = replaceEmbeddedInlineMediaAssetsInVariationData(variationValues[ndx],
targetLanguageCode, resourceResolver);
bVariationValuesUpdated = true;
}
}
if (bVariationValuesUpdated) {
CFEmbeddedAssetUtil.ContentFragmentValueWrapper.setValue(currentVariation, variationValues);
}
}
}
Session session = resourceResolver.adaptTo(Session.class);
try {
// check if session is live and has any pending changes, then we'll save it
if (session != null && session.isLive() && session.hasPendingChanges()) {
session.save();
}
} catch (Exception e) {
// if failed before saving the session then refresh it (skip the current asset)
if (session != null && session.isLive()) {
try {
session.refresh(false); //keepChanges = false (discard all changes to skip the current pending changes)
}
catch (RepositoryException re) {
logger.error("error while refreshing the session: ", re);
}
}
logger.error("Error while replacing the Language copy of Embedded Asset in content element: "
+ (String) currentElement.getName() + " in Content Fragment: " + contentFragmentNodePath + "{}", e);
}
}
}
private static String replaceEmbeddedInlineMediaAssetsInVariationData(String variationData,
String targetLanguageCode, ResourceResolver resourceResolver) {
logger.debug("In Function : replaceEmbeddedInlineMediaAssetsInVariationData");
String regEx = CFEmbeddedAssetUtil.InlineMediaAssetsPatternManager
.getRegexForInlineMediaAssets();
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(variationData);
int lastEnd = 0;
StringBuilder updatedVariationData = new StringBuilder(variationData.length());
while (matcher.find()) {
String sourceCopyPath = CFEmbeddedAssetUtil.InlineMediaAssetsPatternManager
.getMatchingPath(matcher);
sourceCopyPath = decodeURL(sourceCopyPath);
String languageCopyPath = DamLanguageUtil
.findLanguageCopyPathWithAutoCreatedRoots(sourceCopyPath, targetLanguageCode,
resourceResolver);
if (languageCopyPath == null) {
continue;
}
languageCopyPath = encodeURL(languageCopyPath);
CFEmbeddedAssetUtil.RegexIndex regexIndex = CFEmbeddedAssetUtil.InlineMediaAssetsPatternManager.replaceMatchingPath(matcher);
updatedVariationData.append(variationData.substring(lastEnd, regexIndex.getStartIndex()))
.append(languageCopyPath);
lastEnd = regexIndex.getEndIndex();
}
updatedVariationData.append(variationData.substring(lastEnd));
return updatedVariationData.toString();
}
/**
* To get non encoded language copy path for given source path and target language
* @param encodedSourceCopyPath source path can be encoded path
* @param targetLanguageCode target locale code
* @param resourceResolver used to resolve source path to resource object
* @return non encoded language copy path
*/
private static String getLanguageCopyForEncodedURL(String encodedSourceCopyPath,
String targetLanguageCode, ResourceResolver resourceResolver) {
logger.debug("In Function: replaceEmbeddedReferencedAssetsInVariationData");
String sourceCopyPath = decodeURL(encodedSourceCopyPath);
String languageCopyPath = DamLanguageUtil
.findLanguageCopyPathWithAutoCreatedRoots(sourceCopyPath, targetLanguageCode, resourceResolver);
if (languageCopyPath == null) {
logger.error("Language copy not found for {} with target language code {}", encodedSourceCopyPath,
targetLanguageCode);
return null;
}
return languageCopyPath;
}
private static boolean isURLEncoded(String url) {
String decodedURL = decodeURL(url);
return !url.equals(decodedURL);
}
private static String encodeURL(String url) {
try {
return URIUtil.encodePath(url);
} catch (URIException e) {
logger.error("could not encode url : {}", url, e);
return url;
}
}
private static String decodeURL(String url) {
try {
return URIUtil.decode(url);
} catch (URIException e) {
logger.error("could not decode url : {}", url, e);
return url;
}
}
private static boolean isElementFragmentOrContentReference(ContentElement contentElement) {
String semanticType = contentElement.getValue().getDataType().getSemanticType();
return SemanticDataType.REFERENCE.equals(semanticType)
|| SemanticDataType.CONTENT_FRAGMENT.equals(semanticType);
}
private static Set getEmbeddedInlineMediaAssets(String variationData) {
logger.debug("In Function: getEmbeddedInlineMediaAssets");
Set assetPaths = new HashSet<>();
String regEx = CFEmbeddedAssetUtil.InlineMediaAssetsPatternManager.getRegexForInlineMediaAssets();
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(variationData);
while (matcher.find()) {
assetPaths.add(CFEmbeddedAssetUtil.InlineMediaAssetsPatternManager.getMatchingPath(matcher));
}
return assetPaths;
}
private static boolean hasLanguageRoot(@Nonnull String path) {
return LanguageUtil.getLanguageRoot(path) != null;
}
private static class InlineMediaAssetsPatternManager {
private static final String TOKEN_IMAGE_TAG = "img";
private static final String TOKEN_ATTRIBUTE_IMAGE = "src";
private static final String TOKEN_ANCHOR_TAG = "a";
private static final String TOKEN_ATTRIBUTE_LINK = "href";
private static String getRegexForInlineMediaAssets() {
return regexForSrc() + "|" + regexForAnchor();
}
private static String getMatchingPath(Matcher matcher) {
String path = null;
if(matcher.group(getRegexGroupSrc()) != null) {
path = matcher.group(getRegexGroupSrc());
} else if (matcher.group(getRegexGroupAnchor()) != null) {
path = matcher.group(getRegexGroupAnchor());
}
return path;
}
private static CFEmbeddedAssetUtil.RegexIndex replaceMatchingPath(Matcher matcher) {
int start = 0;
int end = 0;
if(matcher.group(getRegexGroupSrc()) != null) {
start = matcher.start(getRegexGroupSrc());
end = matcher.end(getRegexGroupSrc());
} else if (matcher.group(getRegexGroupAnchor()) != null) {
start = matcher.start(getRegexGroupAnchor());
end = matcher.end(getRegexGroupAnchor());
}
CFEmbeddedAssetUtil.RegexIndex regexIndex = new CFEmbeddedAssetUtil.RegexIndex(start, end);
return regexIndex;
}
private static String regexForSrc() {
return getRegexForInlineMediaAssets(TOKEN_IMAGE_TAG, TOKEN_ATTRIBUTE_IMAGE);
}
private static String regexForAnchor() {
return getRegexForInlineMediaAssets(TOKEN_ANCHOR_TAG, TOKEN_ATTRIBUTE_LINK);
}
private static int getRegexGroupSrc() {
return 4;
}
private static int getRegexGroupAnchor() {
return 11;
}
private static String getRegexForInlineMediaAssets(String tag, String attribute) {
final String TOKEN_UNLIMITED_SPACE = "[\\n ]*";
final String TOKEN_ATTRIBUTE_KEY = "[a-zA-Z-]+";
final String TOKEN_SOURCE_ATTRIBUTE_VALUE = "\"" + TOKEN_UNLIMITED_SPACE + "([^>\" \\n]+)" +
TOKEN_UNLIMITED_SPACE + "\"";
final String TOKEN_ATTRIBUTE_VALUE = "\"" + TOKEN_UNLIMITED_SPACE + "([^>\"\\n]+)" + TOKEN_UNLIMITED_SPACE
+ "\"";
final String TOKEN_UNLIMITED_KEY_VALUE = "((" + TOKEN_ATTRIBUTE_KEY + TOKEN_UNLIMITED_SPACE +
"=" + TOKEN_UNLIMITED_SPACE + TOKEN_ATTRIBUTE_VALUE + ")* *)*";
final String TOKEN_SOURCE_KEY_VALUE = attribute + TOKEN_UNLIMITED_SPACE +
"=" + TOKEN_UNLIMITED_SPACE + TOKEN_SOURCE_ATTRIBUTE_VALUE;
final String regex = "<"
+ TOKEN_UNLIMITED_SPACE + tag
+ TOKEN_UNLIMITED_SPACE + TOKEN_UNLIMITED_KEY_VALUE
+ TOKEN_UNLIMITED_SPACE + TOKEN_SOURCE_KEY_VALUE
+ TOKEN_UNLIMITED_SPACE + TOKEN_UNLIMITED_KEY_VALUE
+ TOKEN_UNLIMITED_SPACE + "\\/?"
+ TOKEN_UNLIMITED_SPACE + ">";
return regex;
}
}
private static class RegexIndex {
private int startIndex;
private int endIndex;
RegexIndex(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
private int getStartIndex() {
return startIndex;
}
private int getEndIndex() {
return endIndex;
}
}
private static boolean isContentFragment(Node resourceNode) {
// return resource.adaptTo(ContentFragment.class) == null ? false : true;
try {
if (resourceNode.hasNode(JcrConstants.JCR_CONTENT)) {
Node resourceNodeContent = resourceNode.getNode(JcrConstants.JCR_CONTENT);
if (resourceNodeContent != null) {
if (resourceNodeContent.hasProperty(CONTENT_FRAGMENT)) {
return resourceNodeContent.getProperty(CONTENT_FRAGMENT)
.getBoolean();
}
}
}
} catch (Exception e) {
logger.error("Unable to identify content fragment property for node", e);
}
return false;
}
}
/**
* This code should maintain parity with {@code com.adobe.cq.wcm.translation.impl.lock.LockProperties}
* Any changes made here should also be reflected in the other class as well
*/
private static class LockProperties {
private boolean isSessionScoped;
private boolean isDeep;
private int retryCount;
/**
* The time-out interval for lock in seconds. Taken for future use.
*/
private long timeOutInterval;
private LockProperties(PropertyBuilder propertyBuilder) {
this.isSessionScoped = propertyBuilder.isSessionScoped;
this.isDeep = propertyBuilder.isDeep;
this.timeOutInterval = propertyBuilder.timeOutInterval;
this.retryCount = propertyBuilder.retryCount;
}
public static class PropertyBuilder {
private boolean isSessionScoped = true;
private boolean isDeep = false;
private long timeOutInterval = Long.MAX_VALUE;
private int retryCount = 5;
public PropertyBuilder setIsSessionScoped(boolean isSessionScoped) {
this.isSessionScoped = isSessionScoped;
return this;
}
public PropertyBuilder setIsDeep(boolean deep) {
this.isDeep = deep;
return this;
}
public PropertyBuilder setTimeOutInterval(long timeOutInterval) {
this.timeOutInterval = timeOutInterval;
return this;
}
public PropertyBuilder setRetryCount(int retryCount) {
this.retryCount = retryCount;
return this;
}
public LockProperties build() {
return new LockProperties(this);
}
}
public boolean isDeep() {
return isDeep;
}
public boolean isSessionScoped() {
return isSessionScoped;
}
public long getTimeOutInterval() {
return timeOutInterval;
}
public int getRetryCount() {
return retryCount;
}
}
/**
* This code should maintain parity with {@code com.adobe.cq.wcm.translation.impl.lock.LockUtil}
* Any changes made here should also be reflected in the other class as well
*/
private static class LockUtil {
private static final Logger log = LoggerFactory.getLogger(LockUtil.class);
private static final int RETRY_WAIT_TIME_MS = 500;
protected static AuthorizationService authorizationService;
/**
* Block to initialize Authorization service
*/
static {
Bundle bundle = FrameworkUtil.getBundle(LockUtil.class);
if (bundle != null) {
BundleContext bundleContext = bundle.getBundleContext();
if (bundleContext != null) {
ServiceReference serviceReference = bundleContext.getServiceReference(AuthorizationService.class.getName());
if (serviceReference != null) {
authorizationService = (AuthorizationService) bundleContext.getService(serviceReference);
}
}
}
}
/**
* Locks a resource with retry mechanism.
*
* @param resource resource to lock
* @return true if the node was locked successfully, false otherwise
* Throws AccessDeniedException if the current user does not have permission to lock the node.
* Throws LockException if the node is already locked by another session.
* Throws TranslationException if any other error occurs while locking the node.
*/
public static Lock lockResource(Resource resource, LockProperties lockProperties) throws
AccessDeniedException, LockException, TranslationException {
if (resource != null) {
Session session = resource.getResourceResolver().adaptTo(Session.class);
return lockContentPath(session, resource.getPath(), lockProperties);
} else {
throw new TranslationException("Failed to lock resource. Resource is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Locks a node with retry mechanism.
*
* @param node Node to be locked
* @return true if the node was locked successfully, false otherwise
* Throws AccessDeniedException if the current user does not have permission to lock the node.
* Throws LockException if the node is already locked by another session.
* Throws TranslationException if any other error occurs while locking the node.
*/
public static Lock lockNode(Node node, LockProperties lockProperties) throws
AccessDeniedException, LockException, TranslationException {
if (node != null) {
String nodePath = getNodePath(node);
Session session = getSessionFromNode(node);
return lockContentPath(session, nodePath, lockProperties);
} else {
throw new TranslationException("Failed to lock resource. Resource is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Unlocks a node.
*
* @param node the node to be unlocked
* @return true if the node was unlocked successfully, false if no lock is there on node. Throws exceptions in case of errors.
* throws AccessDeniedException if the current user does not have permission to unlock the node.
* throws TranslationException if any other error occurs while unlocking the node.
*/
public static boolean unlockNode(Node node) throws TranslationException, AccessDeniedException, LockException {
if (node != null) {
Session session = getSessionFromNode(node);
return unlockContent(session, node);
} else {
throw new TranslationException("Failed to lock resource. Resource is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Unlocks a resource.
*
* @param resource the resource to be unlocked
* @return true if the node was unlocked successfully, false if no lock is there on node. Throws exceptions in case of errors.
* throws AccessDeniedException if the current user does not have permission to unlock the node.
* throws TranslationException if any other error occurs while unlocking the node.
*/
public static boolean unlockResource(Resource resource) throws TranslationException, AccessDeniedException, LockException {
if (resource != null) {
Session session = resource.getResourceResolver().adaptTo(Session.class);
Node contentNode = resource.adaptTo(Node.class);
if (contentNode != null) {
return unlockContent(session, contentNode);
} else {
String errorMsg = String.format("Failed to adapt resource [%s] to node.", resource.getPath());
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
throw new TranslationException("Failed to lock resource. Resource is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Checks if the node can be unlocked with same user or administrative access.
*
* @param node the node to be unlocked.
* @return true if the node can be unlocked, false otherwise
* Throws TranslationException if any error occurs while checking the lock.
*/
public static boolean canUnlockWithAdministrativeAccess(Node node) throws TranslationException, RepositoryException {
Session session = getSessionFromNode(node);
if (session != null) {
if (canUnlock(node)) {
return true;
} else if (authorizationService.hasAdministrativeAccess(session)) {
return true;
}
}
return false;
}
/**
* Checks if the node can be unlocked with same user
*
* @param node the node to be unlocked.
* @return true if the node can be unlocked, false otherwise
* Throws TranslationException if any error occurs while checking the lock.
*/
public static boolean canUnlock(Node node) throws TranslationException {
Session session = getSessionFromNode(node);
if (session!=null) {
String lockOwner = getLockOwner(node);
if (lockOwner.equals(session.getUserID())) {
return true;
}
}
return false;
}
/**
* Gets the lock owner of a node.
*
* @param node the node to get the lock owner for.
* @return the lock owner of the node
* Throws TranslationException if any error occurs while getting the lock owner.
*/
public static String getLockOwner(Node node) throws TranslationException {
Session session = getSessionFromNode(node);
String nodePath = getNodePath(node);
try {
LockManager lockManager = getLockManager(session);
Lock lock = lockManager.getLock(nodePath);
return lock.getLockOwner();
} catch (RepositoryException e) {
String errorMsg = String.format("Error while getting lock owner for node [%s]", nodePath);
log.error(errorMsg);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Checks if the node is locked.
*
* @param node the node to be checked
* @return true if the node is locked, false otherwise
* Throws TranslationException if any error occurs while checking the lock.
*/
public static boolean isLocked(Node node) throws TranslationException {
Session session = getSessionFromNode(node);
String nodePath = getNodePath(node);
if (session!=null) {
LockManager lockManager = getLockManager(session);
try {
return lockManager.isLocked(nodePath);
} catch (RepositoryException e) {
String errorMsg = String.format("Error while checking if node [%s] is locked", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
String errorMsg = String.format("Failed to check if node [%s] is locked. Session is null", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Gets the lock of a node.
* @param node the node to get the lock
* @return the lock of the node
* @throws TranslationException if any error occurs while getting the lock.
*/
public static Lock getLock(Node node) throws TranslationException {
Session session = getSessionFromNode(node);
String nodePath = getNodePath(node);
if (session!=null) {
LockManager lockManager = getLockManager(session);
try {
return lockManager.getLock(nodePath);
} catch (RepositoryException e) {
String errorMsg = String.format("Error while getting lock for node [%s]", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
String errorMsg = String.format("Failed to get lock for node [%s]. Session is null", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
/**
* Adds a lock token to a node.
*
* @param node the node to add the lock token for.
* Throws TranslationException if any error occurs while adding the lock token.
*/
public static void addNodeLockToken(Node node) throws TranslationException {
Session session = getSessionFromNode(node);
String nodePath = getNodePath(node);
if (session!=null) {
LockManager lockManager = getLockManager(session);
try {
lockManager.addLockToken(nodePath);
} catch (RepositoryException e) {
String errorMsg = String.format("Error while adding lock token for node [%s]", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
String errorMsg = String.format("Failed to add lock token for node [%s]. Session is null", nodePath);
throw new TranslationException(errorMsg, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
private static LockManager getLockManager(Session session) throws TranslationException {
LockManager lockManager;
try {
lockManager = session.getWorkspace().getLockManager();
} catch (RepositoryException e) {
String errorMessage = "Failed to get LockManager from session";
log.error(errorMessage, e);
throw new TranslationException(errorMessage, e, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
return lockManager;
}
private static boolean unlockContent(Session session, Node contentNode) throws TranslationException, LockException, AccessDeniedException {
if (session != null) {
LockManager lockManager = getLockManager(session);
String contentPath = getNodePath(contentNode);
try {
if (lockManager.isLocked(contentPath)) {
lockManager.unlock(contentPath);
return true;
} else {
log.warn("Node {} is not locked.", contentPath);
return false;
}
} catch (AccessDeniedException e) {
String errorMessage = String.format("Failed to unlock Node lock on node [%s]. Access denied to unlock node.",
contentPath);
log.error(errorMessage, e);
throw e;
} catch (RepositoryException e) {
String errorMessage = String.format("Failed to unlock Node lock on node [%s].",
contentPath);
log.error(errorMessage);
throw new TranslationException(errorMessage, e, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
throw new TranslationException("Failed to unlock node. Session is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
private static Lock lockContentPath(Session session, String contentPath, LockProperties lockProperties)
throws AccessDeniedException, LockException, TranslationException {
if (session != null) {
LockManager lockManager = getLockManager(session);
Node lockableNode = getLockableNode(contentPath, session);
String lockablePath = getNodePath(lockableNode);
Lock lock = obtainLock(session, lockablePath, lockProperties, lockManager);
if (lock != null) {
log.info("Node {} locked successfully.", contentPath);
return lock;
} else {
throw new TranslationException("Failed to lock node " + contentPath, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
} else {
throw new TranslationException("Failed to lock node. Session is null.", TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
private static Lock obtainLock(Session session, String nodePath, LockProperties lockProperties, LockManager lockManager)
throws AccessDeniedException, LockException, TranslationException {
boolean isDeep = lockProperties.isDeep();
boolean isSessionScoped = lockProperties.isSessionScoped();
long timeOutInterval = lockProperties.getTimeOutInterval();
int retryCount = lockProperties.getRetryCount();
if (session != null && lockManager != null) {
int retryAttempt = 0;
do {
try {
if (session.itemExists(nodePath)) {
Lock lock = lockManager.lock(nodePath, isDeep, isSessionScoped, timeOutInterval, session.getUserID());
session.save();
return lock;
}
} catch (LockException e) {
String errorMessage = String.format("Taking lock on node [%s] failed. Node is already locked by another session", nodePath);
log.error(errorMessage);
if (retryAttempt > retryCount - 1) {
throw e;
}
} catch (AccessDeniedException e) {
String errorMessage = String.format("Taking lock on node [%s] failed. Access denied to lock node", nodePath);
log.error(errorMessage);
if (retryAttempt > retryCount - 1) {
throw e;
}
} catch (RepositoryException e) {
String errorMessage = String.format("Taking lock on node [%s] failed.", nodePath);
log.error(errorMessage);
if (retryAttempt > retryCount - 1) {
throw new TranslationException("Failed to lock node " + nodePath, e, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
if (retryCount >= 1) {
long waitMS = ((long) Math.pow(2, retryAttempt)) * RETRY_WAIT_TIME_MS;
String retryMessage = String.format("Retry to take lock on node [%s]. Wait for [%s] ms. Retry count index: [%s].",
nodePath, waitMS, retryAttempt + 1);
log.error(retryMessage);
try {
Thread.sleep(waitMS);
} catch (InterruptedException e1) {
log.error("Thread is interrupted while waiting to take lock on node");
}
}
retryAttempt++;
} while (retryAttempt <= retryCount);
}
return null;
}
private static Node getLockableNode(String nodePath, Session session) throws TranslationException {
try {
Node lockableNode = session.getNode(nodePath);
if (lockableNode.canAddMixin(JcrConstants.MIX_LOCKABLE)) {
lockableNode.addMixin(JcrConstants.MIX_LOCKABLE);
session.save();
}
return lockableNode;
} catch (RepositoryException ex) {
String errorMessage = String.format("Failed to get lockable node for the resource path [%s].",
nodePath);
log.error(errorMessage);
throw new TranslationException(errorMessage, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
private static String getNodePath(Node node) throws TranslationException {
try {
return node.getPath();
} catch (RepositoryException e) {
String errorMessage = "Failed to get path of lockable node";
log.error(errorMessage);
throw new TranslationException(errorMessage, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
private static Session getSessionFromNode(Node node) throws TranslationException {
try {
return node.getSession();
} catch (RepositoryException e) {
String errorMessage = "Failed to get session from node";
log.error(errorMessage);
throw new TranslationException(errorMessage, TranslationException.ErrorCode.GENERAL_EXCEPTION);
}
}
}
// Methods copied from wcm-reactor and updated to read Rule File and get the Ready For Loc related tag info
private static String getTranslationRulesFileLocation(ResourceResolver resolver, boolean bWrite)
throws RepositoryException, PersistenceException {
String strRetVal = null;
// we need to check which file exists in priority order
for (int index = 0; index < RULE_FILES_PRIORITY_ARRAY.length; index++) {
String strCurrentPath = RULE_FILES_PRIORITY_ARRAY[index];
if (resolver.getResource(strCurrentPath) != null) {
strRetVal = strCurrentPath;
break;
}
}
if (bWrite && !LEGACY_ETC_RULES_FILE_PATH.equals(strRetVal)) {
strRetVal = CONF_RULES_FILE_PATH; // write to conf only
// write to conf only if it is not etc path, other wise write to etc only
}
if (LEGACY_ETC_RULES_FILE_PATH.equals(strRetVal)) {
log.info("falling back to {} path, which is obselete, please upgrade this path", strRetVal);
}
if (bWrite && null != strRetVal && resolver.getResource(strRetVal) == null) {
Session session = resolver.adaptTo(Session.class);
// we need to create parent folder structure.
JcrUtils.getOrCreateByPath(Text.getRelativeParent(strRetVal, 1), false, JcrConstants.NT_FOLDER,
JcrConstants.NT_FOLDER, session, true);
Workspace workspace = session.getWorkspace();
workspace.copy(LIBS_RULES_FILE_PATH, strRetVal);
resolver.commit();
}
return strRetVal;
}
private static HashMap getCQTagMapFromRules(ResourceResolver resolver) throws RepositoryException, IOException {
String ruleFilePath = getTranslationRulesFileLocation(resolver, false);
Resource resource = resolver.getResource(ruleFilePath);
if (resource != null) {
javax.jcr.Node node = resource.adaptTo(javax.jcr.Node.class);
if (node != null) {
javax.jcr.Node jcrContent = node.getNode(JcrConstants.JCR_CONTENT);
InputStream contentStream = jcrContent.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(contentStream);
final org.w3c.dom.Node rootNode = doc.getFirstChild();
final NodeList nodeList = rootNode.getChildNodes();
//need to maintain the order of the list of tags in the rule file
HashMap contentFilterTagList = new LinkedHashMap<>();
for (int index = 0; index < nodeList.getLength(); index++) {
org.w3c.dom.Node childNode = nodeList.item(index);
if (childNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
if (ELEMENT_CONTENT_FILTER_NODE.equals(childNode.getNodeName())) {
processContentFilterNode(childNode, contentFilterTagList);
}
}
}
return contentFilterTagList;
} catch (Exception e) {
log.error("Error in getting rfl tag maps from rules");
}
}
} else {
log.debug("Resource not found in path: " + ruleFilePath);
}
return null;
}
private static void processContentFilterNode(org.w3c.dom.Node currentNode, HashMap contentFilterTagList) {
if (currentNode != null) {
String valueListStr =
getElementAttribute((Element) currentNode, ATTRIBUTE_CONTENT_FILTER_VALUE, "");
Boolean createLangCopy =
getElementAttribute((Element) currentNode, ATTRIBUTE_CONTENT_CREATE_LANG_COPY, true);
if(!valueListStr.isEmpty()) {
if(valueListStr.contains(",")){
String[] tagList = valueListStr.split(",");
for(String tag: tagList){
contentFilterTagList.put(tag,createLangCopy);
}
} else {
contentFilterTagList.put(valueListStr,createLangCopy);
}
}
}
}
private static String getElementAttribute(Element element, String strAttributeName, String strDefaultValue) {
return element.hasAttribute(strAttributeName) ? element.getAttribute(strAttributeName) : strDefaultValue;
}
private static boolean getElementAttribute(Element element, String strAttributeName, boolean bDefault) {
String strAttributeValue = getElementAttribute(element, strAttributeName, null);
boolean bRetVal = bDefault;
if (strAttributeValue != null) {
if (strAttributeValue.equalsIgnoreCase("true")) {
bRetVal = true;
} else if (strAttributeValue.equalsIgnoreCase("false")) {
bRetVal = false;
}
}
return bRetVal;
}
private static ArrayList getCqTagsValueList(Property prop) throws RepositoryException{
ArrayList tagList = new ArrayList<>();
// getting the tags from node
if (prop.isMultiple()) {
javax.jcr.Value[] val_array = prop.getValues();
if (val_array != null && val_array.length > 0) {
for (int index = 0; index < val_array.length; index++) {
javax.jcr.Value value = val_array[index];
String strTagName = value.getString();
if (!tagList.contains(strTagName)) {
tagList.add(strTagName);
}
}
}
}
return tagList;
}
private static boolean isNodeReadyForLocalization(Resource srcResource, ResourceResolver resolver){
try {
ArrayList rflTagList = new ArrayList<>();
rflTagList.addAll(getCQTagMapFromRules(resolver).keySet());
if(rflTagList.isEmpty()){
return true;
}
if (null != srcResource.adaptTo(Asset.class)) {
javax.jcr.Node assetSrcNode = srcResource.adaptTo(javax.jcr.Node.class);
if (assetSrcNode.hasNode(JcrConstants.JCR_CONTENT)) {
javax.jcr.Node nodeContent = assetSrcNode.getNode(JcrConstants.JCR_CONTENT);
if (nodeContent != null) {
if (nodeContent.hasNode(METADATA)) {
javax.jcr.Node nodeMetadata = nodeContent.getNode(METADATA);
if (nodeMetadata.hasProperty(CQ_TAG_NAME)) {
Property prop = nodeMetadata.getProperty(CQ_TAG_NAME);
ArrayList tagList = getCqTagsValueList(prop);
for (String ruleTag : rflTagList) {
if (tagList.contains(ruleTag)) {
return false;
}
}
}
}
}
}
}
} catch (RepositoryException | IOException e) {
log.error("Error in getting is node ready for localization");
}
return true;
}
private static boolean isCreateLangCopyForRFLResource(Resource srcResource, ResourceResolver resolver) {
try {
HashMap rflTagMap = getCQTagMapFromRules(resolver);
if(rflTagMap == null || rflTagMap.isEmpty()) {
return true;
}
if (null != srcResource.adaptTo(Asset.class)) {
javax.jcr.Node assetSrcNode = srcResource.adaptTo(javax.jcr.Node.class);
if (assetSrcNode.hasNode(JcrConstants.JCR_CONTENT)) {
javax.jcr.Node nodeContent = assetSrcNode.getNode(JcrConstants.JCR_CONTENT);
if (nodeContent != null) {
if (nodeContent.hasNode(METADATA)) {
javax.jcr.Node nodeMetadata = nodeContent.getNode(METADATA);
if (nodeMetadata.hasProperty(CQ_TAG_NAME)) {
Property prop = nodeMetadata.getProperty(CQ_TAG_NAME);
ArrayList tagList = getCqTagsValueList(prop);
boolean retVal = true;
for (String tag : rflTagMap.keySet()) {
// get the value for last present tag on the rule since rflTagMap is LinkedHashMap
if(tagList.contains(tag)){
retVal = rflTagMap.get(tag);
}
}
return retVal;
}
}
}
}
}
} catch (RepositoryException | IOException e) {
log.error("Error in getting is create lang copy for RFL tag");
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy