All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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.image.Layer;
import com.day.text.Text;

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.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;

import java.io.InputStream;
import java.text.NumberFormat;
import java.util.Arrays;
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;

/**
 * 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[] LAYER_UNSUPPORTED_MIME_TYPES = {
            "image/tiff"};
    private static final List LAYER_UNSUPPORTED_MIME_TYPE = Arrays.asList(LAYER_UNSUPPORTED_MIME_TYPES);

    /**
     * To check weather asset falls under UnSupported category.
     *
     * @param asset
     * @return True if asset type is not supported.
     */
    private static boolean isLayerUnSupported(String mimetype) {
        return LAYER_UNSUPPORTED_MIME_TYPE.contains(mimetype);
    }

    /**
     * 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 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 long width, long height, slingRequest * @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")); } /** * 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 //todo: remove for AEM 6.2 public static String lookupMimeType(String mimeType, Node node, boolean uppercase) { try { if (node == null || mimeType == null) return null; mimeType = mimeType.toUpperCase(); NodeIterator it = node.getNodes(); while (it.hasNext()) { Node child = it.nextNode(); String list = child.getProperty("mimetypes").getString(); int ind; if (list != null) { list = list.replaceAll("\\s", ""); list = list.toUpperCase(); if ((ind = list.indexOf(mimeType)) != -1 && ((ind == 0) || ((ind - 1 >= 0) && (list.charAt(ind - 1) == ',')))) { int end = ind + mimeType.length(); if ((list.charAt(end) == ',' || list.charAt(end) == ';')) if (uppercase) { return child.getProperty("jcr:description").getString(); } else { return child.getProperty("jcr:title").getString(); } } } } } catch (Exception e) { log.error(e.getMessage()); } return null; } /** * 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