
com.day.cq.dam.commons.util.UIHelper Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.day.cq.dam.commons.util;
import com.day.cq.commons.LabeledResource;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.Rendition;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.NameConstants;
import com.day.cq.wcm.api.Page;
import com.day.text.Text;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.resource.collection.ResourceCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provides various utility methods pertaining to DAM required
* in presentation/user interface.
*/
public class UIHelper {
private static final Logger log = LoggerFactory.getLogger(UIHelper.class);
private static final String CONTENT_FRAGMENT = "contentFragment";
private static final String ASSET_REPORT_ITEM = "dam/gui/coral/components/admin/reports/viewreport/items/assetreportitem";
/**
* Returns the title of a resource.
* returns dc:title
metadata property is return if resource represents a DAM asset
* returns Page title if the resource represents a cq:Page
* returns title if it is a {@link LabeledResource}
* in other cases, it returns name of the resource or jcr:title property if exists
*
* @param res a resource
* @return title of the resource
*/
public static String getTitle(Resource res) {
String title = null;
try {
Node resNode = res.adaptTo(Node.class);
if (null != resNode && resNode.isNodeType(DamConstants.NT_DAM_ASSET)) {
Node metadata = resNode.getNode(JcrConstants.JCR_CONTENT + "/metadata");
if (metadata != null && metadata.hasProperty(DamConstants.DC_TITLE)) {
Property property = metadata.getProperty(DamConstants.DC_TITLE);
if(property.isMultiple()){
title = property.getValues()[0].getString();
} else {
title = property.getValue().getString();
}
}
} else if (null != resNode && resNode.isNodeType(NameConstants.NT_PAGE)) {
Page page = res.adaptTo(Page.class);
title = page.getPageTitle();
if (StringUtils.isBlank(title)) {
if (resNode.hasNode(JcrConstants.JCR_CONTENT)) {
Node contentNode = resNode.getNode(JcrConstants.JCR_CONTENT);
if (contentNode.hasProperty(JcrConstants.JCR_TITLE)) {
title = contentNode.getProperty(JcrConstants.JCR_TITLE).getString();
}
}
}
}
if (null == title) {
LabeledResource lr = res.adaptTo(LabeledResource.class);
if (lr != null) {
title = lr.getTitle();
} else {
if (null != resNode && resNode.hasProperty(JcrConstants.JCR_TITLE)) {
title = resNode.getProperty(JcrConstants.JCR_TITLE).getString();
}
}
}
} catch (Exception ex) {
log.error("error in get title ", ex);
}
if (title != null && !title.equals("")) {
return title;
}
return Text.getName(res.getPath());
}
/**
* Returns best fit rendition, whose width is nearer to given width.
* First it tries to look for thumbnail name starting with "cq5dam.thumbnail.width".
* If such a perfect match is not found, then it tries to look for nearest match by looking at rendition
* width.
*
* @param asset dam asset
* @param width width of thumbnail in pixels
* @return Rendition best fit rendition
*/
public static Rendition getBestfitRendition(Asset asset, int width) {
List renditions = asset.getRenditions();
return DamUtil.getBestFitRendition(width, renditions);
}
/**
* Returns alternate text that is to be used in place of the image when
* displaying the resource's thumbnail
*
* @param resource The resource whose alt text need to be found.
* @return The alternate text that is to be used in place of the image/thumbnail.
*/
public static String getAltText(final Resource resource) {
String altText = "";
if (null != resource) {
ResourceResolver resourceResolver = resource.getResourceResolver();
ValueMap vm = resource.adaptTo(ValueMap.class);
if (DamConstants.NT_DAM_ASSET.equals(vm.get(JcrConstants.JCR_PRIMARYTYPE, String.class))) {
altText = getAssetAltText(vm);
} else if (ASSET_REPORT_ITEM.equals(resource.getResourceType())) {
Resource res = resourceResolver.getResource(resource.getPath());
//if the resource exists i.e. has not been deleted/moved since the report was created
if (null != res) {
altText = getAssetAltText(res.adaptTo(ValueMap.class));
}
} else if (vm.get(JcrConstants.JCR_CONTENT + "/" + CONTENT_FRAGMENT, false)) {
altText = getCfmOrCollectionAltText(vm, JcrConstants.JCR_CONTENT + "/");
} else if (resource.adaptTo(ResourceCollection.class) != null) {
altText = getCfmOrCollectionAltText(vm, "");
}
}
return (StringUtils.isBlank(altText) && null != resource) ? resource.getName() : altText;
}
/**
* Returns alternate text that should be shown while displaying the CFM/Collection's thumbnail
*/
private static String getCfmOrCollectionAltText(ValueMap vm, String pathConstant) {
String altText = "";
String description = vm.get(pathConstant +JcrConstants.JCR_DESCRIPTION, String.class);
String title = vm.get(pathConstant + JcrConstants.JCR_TITLE, String.class);
if (!StringUtils.isBlank(description)) {
altText = description;
} else if (!StringUtils.isBlank(title)) {
altText = title;
}
return altText;
}
/**
* Returns alternate text that should be shown while displaying the asset's thumbnail
*/
private static String getAssetAltText(ValueMap vm) {
String altText = "";
String description = vm.get(JcrConstants.JCR_CONTENT + "/" + DamConstants.METADATA_FOLDER + "/" + DamConstants.DC_DESCRIPTION, String.class);
String title = vm.get(JcrConstants.JCR_CONTENT + "/" + DamConstants.METADATA_FOLDER + "/" + DamConstants.DC_TITLE, String.class);
String name = vm.get(JcrConstants.JCR_CONTENT + "/" + DamConstants.PN_NAME , String.class);
if (!StringUtils.isBlank(description)) {
altText = description;
} else if (!StringUtils.isBlank(title)) {
altText = title;
} else if (!StringUtils.isBlank(name)) {
altText = name;
}
return altText;
}
/**
* Returns the cache killer number that can be appended the resource request.
*
* @param node a node
* @return a number which represent last modified timestamp of node/resource
*/
public static long getCacheKiller(Node node) {
long ck = 0;
try {
if (node.isNodeType(DamConstants.NT_DAM_ASSET) || node.isNodeType(JcrConstants.NT_FILE)) {
// ck for asset/rendition is the jcr:content/jcr:lastModified
if (node.hasProperty("jcr:content/jcr:lastModified")) {
ck = node.getProperty("jcr:content/jcr:lastModified").getLong();
}
} else if (node.isNodeType(JcrConstants.NT_FOLDER)) {
// ck for directory is
// jcr:content/folderthumbnail/jcr:lastModified
if (node.hasProperty("jcr:content/folderThumbnail/jcr:content/jcr:lastModified")) {
ck = node.getProperty("jcr:content/folderThumbnail/jcr:content/jcr:lastModified").getLong();
}
} else if (node.hasProperty("jcr:lastModified")) {
ck = node.getProperty("jcr:lastModified").getLong();
}
} catch (Exception e) {
log.error("error creating cache killer", e);
}
// remove milliseconds in order to match the mod date provided by json servlets
return ck / 1000 * 1000;
}
/**
* returns the resource represented by the suffix.
* if the request path is assets.html/content/dam, it will return suffix represnted by /content/dam
* in case of invalid paths, it defaults to /content/dam
*
* @param request sling request
* @return suffix resource
*/
public static Resource getCurrentSuffixResource(SlingHttpServletRequest request) {
String contentPath = request.getRequestPathInfo().getSuffix();
Resource res = request.getResourceResolver().getResource(contentPath);
if (contentPath == null || !contentPath.contains(DamConstants.MOUNTPOINT_ASSETS) || res == null) {
return request.getResourceResolver().getResource(DamConstants.MOUNTPOINT_ASSETS);
}
return res;
}
/**
* Adds units to given size in bytes and create label to be displayed in UI
*
* @param size size in bytes
* @return string label for file/asset size.
*/
public static String getSizeLabel(double size) {
//this method will represent the size in KB, MB, GB and TB appropriately
String units[] = {"B", "KB", "MB", "GB", "TB"};
int i;
for (i = 0; size >= 1024; i++) {
size = size / 1024;
}
return Math.round(size * Math.pow(10, 1)) / Math.pow(10, 1) + " " + units[i];
}
/**
* Adds units to given size in bytes and create label to be displayed in UI
* and Internationalize the result.
*
* @param size size in bytes
* @return string label for file/asset size.
*/
public static String getSizeLabel(double size, SlingHttpServletRequest slingRequest) {
Locale locale = slingRequest.getResourceBundle(null).getLocale();
I18n i18n = new I18n(slingRequest);
// this method will represent the size in KB, MB, GB and TB
// appropriately
int i;
for (i = 0; size >= 1024; i++) {
size = size / 1024;
}
NumberFormat nf = NumberFormat.getInstance(locale);
String formattedSize = nf.format(Math.round(size * Math.pow(10, 1)) / Math.pow(10, 1));
switch (i) {
case 0:
return i18n.get("{0} B", "Byte", formattedSize);
case 1:
return i18n.get("{0} KB", "KiloByte", formattedSize);
case 2:
return i18n.get("{0} MB", "MegaByte", formattedSize);
case 3:
return i18n.get("{0} GB", "GigaByte", formattedSize);
case 4:
return i18n.get("{0} TB", "TeraByte", formattedSize);
default:
return "";
}
}
/**
* Display resolution with correct i18n number formatting
*
* @param width width
* @param height height
* @param slingRequest request
* @return string label for resolution in i18n'ed format of: width x height
*/
public static String getResolutionLabel(long width, long height, SlingHttpServletRequest slingRequest) {
Locale locale = slingRequest.getResourceBundle(null).getLocale();
I18n i18n = new I18n(slingRequest);
NumberFormat nf = NumberFormat.getInstance(locale);
String formattedWidth = nf.format(width);
String formattedHeight = nf.format(height);
return i18n.get("{0} x {1}", "width x height, image resolution", formattedWidth, formattedHeight);
}
/**
* returns whether the given resource has the permission to perform the
* privileged action
*
* @param acm AccessControlManager to determine the permissions
* @param res resource
* @param privilege action, wanted to perform on the res
* @return true if user has the permission, otherwise false
* @throws RepositoryException
*/
public static boolean hasPermission(AccessControlManager acm, Resource res, String privilege) throws RepositoryException {
Privilege p = acm.privilegeFromName(privilege);
return acm.hasPrivileges(res.getPath(), new Privilege[]{p});
}
/**
* returns the privileges the session has for the given resource
*
* @param acm AccessControlManager to determine the permissions
* @param res resource
* @return returns the privileges for the resource
* @throws RepositoryException
* @throws PathNotFoundException
*/
public static Privilege[] getAllPermission(AccessControlManager acm, Resource res) throws PathNotFoundException, RepositoryException {
return acm.getPrivileges(res.getPath());
}
/**
* returns whether Interactive Edit(crop/rotate) operations are supported on
* the given mimetype
*
* @param mimetype
* @return
*/
public static boolean isEditSupportedFormat(String mimetype) {
String supportedTypes[] = {"image/jpg", "image/jpeg", "image/png", "image/gif", "image/bmp"};
for (String type : supportedTypes) {
if (type.equalsIgnoreCase(mimetype)) {
return true;
}
}
return false;
}
/**
* Returns best fit rendition, whose size is nearer to given size.
*
* @param asset dam asset
* @param size size in KB
* @return Rendition best fit rendition
*/
public static Rendition getBestFitRendtionBasedOnSize(final Asset asset, final long size) {
return getBestFitRendtionBasedOnSize(asset, size, false);
}
/**
* Returns best fit rendition, whose size is nearer to given size.
*
* @param asset dam asset
* @param size size in KB
* @param preferOriginal return original if size of best fit rendition is greater
* @return Rendition best fit rendition
*/
public static Rendition getBestFitRendtionBasedOnSize(final Asset asset, final long size,
boolean preferOriginal) {
try {
long sizeinBytes = size * 1024;
List renditions = asset.getRenditions();
UIHelper.SizeBasedRenditionComparator comp = new UIHelper.SizeBasedRenditionComparator();
Collections.sort(renditions, comp);
Iterator itr = renditions.iterator();
Rendition bestFit = null;
while (itr.hasNext()) {
Rendition rend = itr.next();
if (canRenderOnWeb(rend.getMimeType())) {
if (rend.getSize() <= sizeinBytes) {
bestFit = rend;
}
}
}
// if all renditions are larger then given size, find rendition
// closest to size;
if (bestFit == null) {
itr = renditions.iterator();
while (itr.hasNext()) {
Rendition rend = itr.next();
if (canRenderOnWeb(rend.getMimeType())) {
bestFit = rend;
break;
}
}
} else if (preferOriginal) {
// prefer original when size of original is smaller than bestFit
// rendition & can be rendered on WEB
// Not applicable when all renditions are greater than size
// given
if (canRenderOnWeb(asset.getOriginal().getMimeType())
&& bestFit.getSize() > asset.getOriginal().getSize()) {
return asset.getOriginal();
}
}
return bestFit;
} catch (Exception e) {
log.error("Error occured while getting best fit rendition ", e);
return null;
}
}
/**
* Returns true if the given mime type can be rendered in HTML by browser.
*
* @param mimeType
* @return
*/
public static boolean canRenderOnWeb(final String mimeType) {
return mimeType != null && (mimeType.toLowerCase().contains("jpeg")
|| mimeType.toLowerCase().contains("jpg")
|| mimeType.toLowerCase().contains("gif")
|| mimeType.toLowerCase().contains("png")
|| mimeType.toLowerCase().contains("bmp"));
}
/**
* Returns the width of rendition if it is the original rendition,
* and has dimension metadata, or if it follows the naming convention
* cq5dam.[thumbnail|web].width.height.ext,else 0
*
* @param r Rendition whose width is required
* @return width if it follows the naming convention, else 0
*/
public static int getWidth(final Rendition r) {
return getDimension(r, DamConstants.TIFF_IMAGEWIDTH);
}
/**
* Returns the height of rendition if it is the original rendition,
* and has dimension metadata, or if it follows the naming convention
* cq5dam.[thumbnail|web].width.height.ext,else 0
*
* @param r Rendition whose width is required
* @return width if it follows the naming convention, else 0
*/
public static int getHeight(final Rendition r) {
return getDimension(r, DamConstants.TIFF_IMAGELENGTH);
}
// assuming convention cq5dam.[thumbnail|web].width.height.ext Note: This would be better with named regex starting in java 1.7
private static final Pattern renditionPattern = Pattern.compile("cq5dam\\.(.*)?\\.(\\d+)\\.(\\d+)\\.(.*)");
private static final int PATTERN_WIDTH_INDEX = 2;
private static final int PATTERN_HEIGHT_INDEX = 3;
//package scope for unit tests.
private static int getDimension(final Rendition r, final String dimensionProperty) {
if(r == null) {
log.debug("Null rendition at", new Exception("Null rendition"));
return 0;
}
if(dimensionProperty == null || (!dimensionProperty.equals(DamConstants.TIFF_IMAGELENGTH) && !dimensionProperty.equals(DamConstants.TIFF_IMAGEWIDTH))) {
log.warn("Incorrect dimension property for {}", r.getPath(), new Exception("Invalid property name " + dimensionProperty)); //This indicates a programatic error in this class.
return 0;
}
String name = r.getName();
if(name == null) {
log.warn("Null name returned at {}", r.getPath());
return 0;
}
// assuming convention cq5dam.[thumbnail|web].width.height.ext
try {
if(name.equals(DamConstants.ORIGINAL_FILE)) {
Asset asset = r.adaptTo(Asset.class);
if(asset == null) {
log.debug("Rendition at {} is not adaptable to an asset.", r.getPath());
return 0;
}
String val = asset.getMetadataValue(dimensionProperty);
if(val == null || val.length() == 0) {
//This can happen for vector types (PDF, SVG, AI, EPS, etc..) and for assets that have not had their async workflows processed.
log.debug("Unable to find metadata property {} for {}", dimensionProperty, asset.getPath());
return 0;
}
try {
return Integer.parseInt(val);
}
catch(NumberFormatException nfe) {
log.warn("Metadata property {} was {} and not a number at {}", new Object[]{dimensionProperty, val, asset.getPath()});
return 0;
}
}
Matcher matcher = renditionPattern.matcher(name);
if(matcher.matches()) {
final int matcherIndex;
if(DamConstants.TIFF_IMAGELENGTH.equals(dimensionProperty)) {
matcherIndex = PATTERN_HEIGHT_INDEX;
}
else {
matcherIndex = PATTERN_WIDTH_INDEX;
}
int renditionHeight = Integer.parseInt(matcher.group(matcherIndex));
return renditionHeight;
}
else {
log.debug("Unknown naming format for name {} at {}", name, r.getPath());
return 0;
}
} catch (Exception e) {
log.warn("Unexpected exception finding dimension for asset at {} " + r.getPath(), e);
return 0;
}
}
/**
* Please use lookupMimeType(String, Resource, boolean)
*/
@Deprecated
public static String lookupMimeType(String mimeType, Node node, boolean uppercase) {
throw new UnsupportedOperationException("This API has been deprecated. Use lookupMimeType(String, Resource, uppercase) instead.");
}
/**
* does a lookup for the given mimetype in the given resource.
*
* @param mimeType
* @param resource
* @param uppercase
* @return title/description of the matched resource
*/
public static String lookupMimeType(String mimeType, Resource resource,
boolean uppercase) {
try {
if (resource == null || mimeType == null) {
return null;
}
for (Iterator it = resource.listChildren(); it.hasNext();) {
Resource child = it.next();
ValueMap childVM = child.adaptTo(ValueMap.class);
String mimetypes = childVM.get("mimetypes", String.class);
String mimetypesList[] = mimetypes.split(",");
if (ArrayUtils.contains(mimetypesList, mimeType.toUpperCase())) {
if (uppercase) {
return childVM.get(JcrConstants.JCR_DESCRIPTION,
String.class);
} else {
return childVM
.get(JcrConstants.JCR_TITLE, String.class);
}
}
}
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
/**
* Returns true, if an asset is checked out by drive. False otherwise.
*
* @param asset Asset whose status needs to be determined
* @return True if asset is checked out by drive, false otherwise
*/
public static boolean isCheckedOutByDrive(final Asset asset) {
try {
Node assetNode = asset.adaptTo(Node.class);
Node jcrContent = assetNode.getNode("jcr:content");
if (jcrContent != null) {
if (jcrContent.hasProperty("cq:drivelock")) {
return true;
}
}
} catch (PathNotFoundException e) {
log.warn("Asset does not exists ", e);
} catch (RepositoryException e) {
log.warn("Respoitory execption", e);
}
return false;
}
public static String getCheckedOutby(final Asset asset) {
if (isCheckedOutByDrive(asset)) {
try {
Node assetNode = asset.adaptTo(Node.class);
Node jcrContent = assetNode.getNode("jcr:content");
return jcrContent.getProperty("cq:drivelock").getString();
} catch (PathNotFoundException e) {
log.warn("Asset does not exists ", e);
} catch (ValueFormatException e) {
log.warn("Value format exception ", e);
} catch (RepositoryException e) {
log.warn("Respoitory execption", e);
}
}
return "";
}
private static class SizeBasedRenditionComparator implements Comparator {
public int compare(Rendition r1, Rendition r2) {
if (r1.getSize() < r2.getSize()) {
return -1;
} else if (r1.getSize() == r2.getSize()) {
return 0;
} else {
return 1;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy