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.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