
com.day.cq.dam.commons.util.DamUtil Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.dam.commons.util;
import static com.day.cq.commons.jcr.JcrConstants.JCR_CONTENT;
import static com.day.cq.commons.jcr.JcrConstants.NT_FILE;
import static com.day.cq.dam.api.DamConstants.DAM_ASSET_RELATIVE_PATH;
import static com.day.cq.dam.api.DamConstants.MOUNTPOINT_ASSETS;
import static com.day.cq.dam.api.DamConstants.MOUNTPOINT_BINARIES;
import static com.day.cq.dam.api.DamConstants.NT_DAM_ASSET;
import static com.day.cq.dam.api.DamConstants.PREFIX_ASSET_THUMBNAIL;
import static com.day.cq.dam.api.DamConstants.RENDITIONS_FOLDER;
import static com.day.cq.dam.api.DamConstants.METADATA_FOLDER;
import static com.day.cq.dam.api.DamConstants.SUBASSETS_FOLDER;
import static com.day.cq.dam.commons.util.DamConfigurationConstants.DAM_ASSETS_ROOT;
import java.awt.Dimension;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
import javax.jcr.query.qom.Constraint;
import javax.jcr.query.qom.DynamicOperand;
import javax.jcr.query.qom.JoinCondition;
import javax.jcr.query.qom.QueryObjectModel;
import javax.jcr.query.qom.QueryObjectModelConstants;
import javax.jcr.query.qom.QueryObjectModelFactory;
import javax.jcr.query.qom.Source;
import javax.jcr.query.qom.StaticOperand;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.resource.collection.ResourceCollection;
import org.apache.sling.tenant.Tenant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.internal.pdftoolkit.core.util.Utility;
import com.adobe.xmp.XMPDateTime;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.thumbnail.ThumbnailConfig;
import com.day.cq.search.Predicate;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.eval.JcrPropertyPredicateEvaluator;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;
/**
* This class provides various utility methods pertaining to DAM.
*
* @author djaeggi
* @since CQ 5.4.0
*/
public class DamUtil {
private static final Logger log = LoggerFactory.getLogger(DamUtil.class);
private static final String[] IMG_MIME_TYPES = {
DamConstants.THUMBNAIL_MIMETYPE, "image/jpeg", "image/tiff", "image/png",
"image/bmp", "image/gif", "image/pjpeg", "image/x-portable-anymap",
"image/x-portable-bitmap", "image/x-portable-graymap",
"image/x-portable-pixmap", "image/x-rgb", "image/x-xbitmap",
"image/x-xpixmap", "image/x-icon", "image/photoshop",
"image/x-photoshop", "image/psd", "application/photoshop", "application/psd",
"image/vnd.adobe.photoshop"};
private static final String[] VID_MIME_TYPES = { "video/m4v", "video/flv",
"video/avi", "video/mov", "video/3gpp", "application/x-troff-msvideo",
"video/vnd", "model/vnd.mts", "video/ts", "video/vnd", "video/dvd",
"video/x-ms-wmv", "video/msvideo", "video/x-msvideo", "video/x-flv",
"video/mpeg", "video/x-mpeg", "video/x-m4v", "video/mpg",
"video/x-mpg", "video/mpeg2", "video/x-mpeg2a", "video/mts",
"video/x-ms-asf", "video/3gpp2", "video/x-f4v", "video/f4v",
"video/m2p", "video/mp2t", "video/avchd-stream", "video/m2ts",
"video/mp2t", "video/vnd.dlna.mpeg-tts", "video/m2v",
"video/quicktime", "video/x-quicktime", "video/mp4",
"video/ogg", "video/x-mxf", "application/mxf", "video/x-matroska", "video/mj2",
"video/vnd.rn-realvideo", "application/vnd.rn-realmedia", "video/webm" };
private static final List IMG_MIME_TYPE = Arrays.asList(IMG_MIME_TYPES);
private static final List VID_MIME_TYPE = Arrays.asList(VID_MIME_TYPES);
private static final int MAGIC_SIZE = 1024;
/**
* Translates the path of an asset to its congruent DAM binary path, by replacing the /content/dam path
* prefix with /var/dam. If the given path does not start with DAM's asset mountpoint, null
is
* returned.
*
* DamUtil.assetToBinaryPath("/content/dam/myfolder/test.jpg") = "/var/dam/myfolder/test.jpg"
* DamUtil.assetToBinaryPath(null) = null
*
*
* @param path The path to translate.
* @return The binary equivalent path or null
if the given path is not a DAM asset path.
* @see com.day.cq.dam.api.DamConstants#MOUNTPOINT_BINARIES
* @see com.day.cq.dam.api.DamConstants#MOUNTPOINT_ASSETS
*/
public static String assetToBinaryPath(final String path) {
String binaryPath = null;
if (StringUtils.startsWith(path, MOUNTPOINT_ASSETS)) {
binaryPath = StringUtils.replaceOnce(path, MOUNTPOINT_ASSETS, MOUNTPOINT_BINARIES);
}
return binaryPath;
}
/**
* Translates the path of a DAM binary to its congruent asset path, by replacing the /var/dam path prefix
* with /content/dam. If the given path does not start with DAM's binary mountpoint, null
is
* returned.
*
* DamUtil.binaryToAssetPath("/var/dam/myfolder/test.jpg") = "/content/dam/myfolder/test.jpg"
* DamUtil.binaryToAssetPath(null) = null
*
*
* @param path The path to translate.
* @return The metadata equivalent path or null
if the given path is not a DAM binary path.
* @see com.day.cq.dam.api.DamConstants#MOUNTPOINT_BINARIES
* @see com.day.cq.dam.api.DamConstants#MOUNTPOINT_ASSETS
*/
public static String binaryToAssetPath(final String path) {
String assetPath = null;
if (StringUtils.startsWith(path, MOUNTPOINT_BINARIES)) {
assetPath = StringUtils.replaceOnce(path, MOUNTPOINT_BINARIES, MOUNTPOINT_ASSETS);
}
return assetPath;
}
/**
* This method determines whether the given {@link Node} represents a thumbnail of an asset.
*
* @param file The node to check.
* @return true
if the node represent's an asset's thumbnail, false
otherwise.
*/
public static boolean isThumbnail(Node file) {
try {
return (file.isNodeType(NT_FILE) && file.getName().startsWith(PREFIX_ASSET_THUMBNAIL));
} catch (RepositoryException re) {
// ignore
}
return false;
}
/**
* Returns the name of a thumbnail in the DAM thumbnail name format, respecting the given dimensions of the
* thumbnail. E.g. providing a width
of 100 and a height
of 100 would return the thumbnail
* name cq5dam.thumbnail.100.100.png. As a thumbnail represents a rendition of an {@link
* com.day.cq.dam.api.Asset}, the name can be used for easy retrieval of the thumbnail:
*
*
* ...
* final String thumbnailName = DamUtil.getThumbnailName(100, 100);
* final Resource thumbnail = asset.getRendition(thumbnailName);
* ...
*
*
* @param width The width of the thumbnail.
* @param height The height of the thumbnail.
* @return The rendition name of the thumbnail.
*/
public static String getThumbnailName(final int width, final int height) {
return getThumbnailName(width, height, null);
}
/**
* Returns the expected rendition/thumbnail name based on the given thumbnail configuration.
*
* @param config The {@link com.day.cq.dam.api.thumbnail.ThumbnailConfig}
* @return The {@link com.day.cq.dam.api.Rendition} name.
*/
public static String getThumbnailName(final ThumbnailConfig config) {
final String[] selectors = (config.doCenter()) ? new String[]{"margin"} : null;
return getThumbnailName(config.getWidth(), config.getHeight(), selectors);
}
/**
* Behaves like {@link #getThumbnailName(int, int)}. Additionally and optionally a string array of selectors to be
* added to the thumbnail name can be specified. E.g. providing width
= 100, height
= 100
* and selectors
= {"a", "b", "c"} would return the thumbnail name
* cq5dam.thumbnail.100.100.a.b.c.png. Example:
*
*
* ...
* final String[] selectors = {"a", "b", "c"};
* final String thumbnailName = DamUtil.getThumbnailName(100, 100, selectors);
* final Resource thumbnail = asset.getRendition(thumbnailName);
* ...
*
*
* @param width The width of the thumbnail.
* @param height The height of the thumbnail.
* @param selectors An array of selectors to be added. May be null (ignored).
* @return The rendition name of the thumbnail.
*/
public static String getThumbnailName(final int width, final int height, String[] selectors) {
selectors = (null != selectors) ? selectors : new String[0];
String selectorString = StringUtils.join(selectors, '.');
if (!"".equals(selectorString)) {
selectorString = "." + selectorString;
}
return PREFIX_ASSET_THUMBNAIL + "." + String.valueOf(width) + "." + String.valueOf(height) + selectorString
+ ".png";
}
/**
* Checks whether the given {@link Resource} represents a {@link com.day.cq.dam.api.Rendition} of an {@link
* com.day.cq.dam.api.Asset}. The requirements are that given resource
is stored within the
* renditions folder of an asset and that it's node type is nt:file.
*
* @param resource The resource to check.
* @return true
if the resource is a rendition.
*/
public static boolean isRendition(final Resource resource) {
if (null == resource) {
return false;
}
final Resource parent = ResourceUtil.getParent(resource);
if (null == parent) {
return false;
}
final Resource content = ResourceUtil.getParent(parent);
if (null == content) {
return false;
}
final Resource asset = ResourceUtil.getParent(content);
if (null == asset) {
return false;
}
// resource type check was removed with introduction of proxied renditions - see GRANITE-1764
// since the resource type is no longer strictly NT_FILE but can be different as is for
// proxied renditions - the NT_FILE will remain for legacy purposes but anything else
// becomes an implementation detail of Granite Asset Core implementation.
return RENDITIONS_FOLDER.equals(ResourceUtil.getName(parent))
&& (isAsset(asset) || isFrozenNode(asset)); //Added frozen node check for CQ-8592
}
/**
* Returns true if {@link Asset} can be adapted from
* dam:asset/jcr:content/metadata resource else returns false.
*/
public static boolean isMetadataRes(final Resource resource) {
if (null == resource
|| !METADATA_FOLDER.equals(ResourceUtil.getName(resource))) {
return false;
}
final Resource content = ResourceUtil.getParent(resource);
if (null == content) {
return false;
}
final Resource asset = ResourceUtil.getParent(content);
if (null == asset) {
return false;
}
// resource type check was removed with introduction of proxied
// renditions - see GRANITE-1764
// since the resource type is no longer strictly NT_FILE but can be
// different as is for
// proxied renditions - the NT_FILE will remain for legacy purposes but
// anything else
// becomes an implementation detail of Granite Asset Core
// implementation.
return (isAsset(asset) || isFrozenNode(asset)); // Added frozen node
// check for CQ-8592
}
/**
* Returns {@link Asset} for the dam:asset/jcr:content/metadata resource
* else returns null.
*/
public static Asset getAssetFromMetaRes(final Resource resource) {
if (null == resource
|| !METADATA_FOLDER.equals(ResourceUtil.getName(resource))) {
return null;
}
final Resource content = ResourceUtil.getParent(resource);
if (null == content) {
return null;
}
final Resource asset = ResourceUtil.getParent(content);
if (null == asset) {
return null;
}
// resource type check was removed with introduction of proxied
// renditions - see GRANITE-1764
// since the resource type is no longer strictly NT_FILE but can be
// different as is for
// proxied renditions - the NT_FILE will remain for legacy purposes but
// anything else
// becomes an implementation detail of Granite Asset Core
// implementation.
if (isAsset(asset) || isFrozenNode(asset)) {
return asset.adaptTo(Asset.class);
}
return null;
}
/**
* Checks whether the given {@link Resource} represents a {@link com.day.cq.dam.api.Asset}. The requirements are
* that the given resource
is of node type dam:Asset.
*
* @param resource The resource to check.
* @return true
if the resource is an asset.
*/
public static boolean isAsset(final Resource resource) {
return null != resource && NT_DAM_ASSET.equals(resource.getResourceType());
}
/**
* Checks whether the give {@link Resource} represents a frozen node. The requirements are
* that the given resource
is of node type nt:frozenNode.
* @param resource The resource to check
* @return true
if the resource is an asset.
*/
public static boolean isFrozenNode(final Resource resource) {
return null != resource && "nt:frozenNode".equals(resource.getResourceType());
}
/**
* Indicates whether the given resource
is an {@link Asset}'s sub-asset.
*
* @param resource The {@link Resource} to check.
* @return true
if this asset is a sub-asset.
*/
public static boolean isSubAsset(final Resource resource) {
return isAsset(resource) && SUBASSETS_FOLDER.equals(ResourceUtil.getName(ResourceUtil.getParent(resource)));
}
/**
* Checks whether the given resource
is an asset, and if not, travels upwards the resource hierarchy
* until a resource is an asset.
*
* @param resource The resource to check.
* @return The {@link Asset} or null
if no asset was found.
*/
public static Asset resolveToAsset(final Resource resource) {
if (null != resource && isAsset(resource)) {
return resource.adaptTo(Asset.class);
} else {
final Resource parent = ResourceUtil.getParent(resource);
if (null != parent) {
return resolveToAsset(parent);
}
}
return null;
}
/**
* This method updates the "last modified" information of the given {@link Asset}.
*
* @param asset The asset to update.
* @param user The username of who updated the asset.
* @param date The date/time the updated happened.
*/
public static void setModified(final Asset asset, final String user, final Calendar date) {
try {
final Node contentNode = asset.adaptTo(Node.class).getNode(JcrConstants.JCR_CONTENT);
contentNode.setProperty(JcrConstants.JCR_LAST_MODIFIED_BY, user);
contentNode.setProperty(JcrConstants.JCR_LASTMODIFIED, date);
contentNode.getSession().save();
} catch (RepositoryException e) {
// ignore
}
}
/**
* Find all dam assets which are getting expired between lowerBound and upperBound.
*
* @param session
* @param lowerBound the lower bound of date where asset expiration is computed. If null it is not considered as
* query criterion
* @param upperBound the upper bound of date where asset expiration is computed. If null it is not considered as
* query criterion
* @throws RepositoryException
*/
public static List findExpiringAssets(Session session, Calendar lowerBound, Calendar upperBound)
throws RepositoryException {
List results = null;
QueryObjectModel qom = null;
try {
QueryManager queryManager = session.getWorkspace().getQueryManager();
QueryObjectModelFactory qomf = queryManager.getQOMFactory();
Source damAsset = qomf.selector(DamConstants.NT_DAM_ASSET, "selector_0");
Source assetContent = qomf.selector(DamConstants.NT_DAM_ASSETCONTENT, "selector_1");
ValueFactory vf = session.getValueFactory();
DynamicOperand expiryDateOprnd = qomf.propertyValue("selector_1", DamConstants.PN_OFF_TIME);
Constraint expiryDateConstrnt = null;
Constraint upperBndConstrnt = null;
if (upperBound != null) {
StaticOperand upperBndOprnd = qomf.literal(vf.createValue(upperBound));
upperBndConstrnt = qomf.comparison(expiryDateOprnd, QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN,
upperBndOprnd);
expiryDateConstrnt = upperBndConstrnt;
}
if (lowerBound != null) {
StaticOperand lowerBndOprnd = qomf.literal(vf.createValue(lowerBound));
Constraint lowerBndConstrnt = qomf.comparison(expiryDateOprnd,
QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO, lowerBndOprnd);
if(upperBndConstrnt != null ) {
expiryDateConstrnt = qomf.and(upperBndConstrnt, lowerBndConstrnt);
}else {
expiryDateConstrnt = lowerBndConstrnt;
}
}
JoinCondition joinAssetToJcrContent = qomf.sameNodeJoinCondition("selector_1", "selector_0", JcrConstants.JCR_CONTENT);
assetContent = qomf.join(damAsset, assetContent, QueryObjectModelConstants.JCR_JOIN_TYPE_INNER,
joinAssetToJcrContent);
qom = qomf.createQuery(assetContent, expiryDateConstrnt, null, null);
if (log.isDebugEnabled()) {
log.debug("Expiring assets query [{}].", qom.getStatement());
}
long startTime = 0L;
if (log.isTraceEnabled()) {
startTime = System.currentTimeMillis();
}
QueryResult result = qom.execute();
if (log.isTraceEnabled()) {
long endTime = System.currentTimeMillis();
log.trace("Time taken to execute query [{}] ms", new Long(endTime - startTime));
}
RowIterator rowIter = result.getRows();
long resultSize = rowIter.getSize();
results = new ArrayList(new Long(resultSize).intValue());
if (log.isDebugEnabled()) {
log.debug("ResultSet size [{}].", resultSize);
}
if (log.isTraceEnabled()) {
log.trace("Logging search result set");
}
while (rowIter.hasNext()) {
Row row = rowIter.nextRow();
Node node = row.getNode("selector_0");
String path = node.getPath();
if (log.isTraceEnabled()) {
log.trace("path [{}]", path);
}
results.add(path);
}
} catch (RepositoryException e) {
if (qom != null) {
log.error("Expired assets query [{}].", qom.getStatement());
}
log.error("Error in finding expired assets", e);
throw e;
}
return results;
}
/**
* Returns whether the asset has expired.
* @param asset
* @return true, if the asset has expired
*/
public static boolean isExpiredAsset(Asset asset) {
boolean isAssetExpired = false;
if (null != asset) {
Calendar now = Calendar.getInstance();
Calendar assetExpiryTime = getExpiryTime(asset);
if (null != assetExpiryTime) {
isAssetExpired = assetExpiryTime.before(now);
}
}
return isAssetExpired;
}
/**
* Returns whether the resource has expired.
* @param resource
* @return true, if the resource has expired
*/
public static boolean isExpiredAsset(Resource resource) {
return isExpiredAsset(resource.adaptTo(Asset.class));
}
/**
* Returns whether the resource has any subasset which has expired.
*
* @param resource
* @return true, if any of the subasset of the asset has expired
*/
public static boolean isExpiredSubAsset(Resource resource) {
boolean isAssetExpired = false;
boolean isSubAssetExpired = false;
Asset asset = resource.adaptTo(Asset.class);
if (null != asset) {
isAssetExpired = isExpiredAsset(asset);
if (!isAssetExpired) {
Calendar now = Calendar.getInstance();
Collection subAssets = asset.getSubAssets();
List refSubAssets = DamUtil.getReferencedSubAssets(resource);
if (null != refSubAssets) {
subAssets.addAll(refSubAssets);
}
ResourceResolver resolver = resource.getResourceResolver();
for (Asset each : subAssets) {
Resource subRes = resolver.getResource(each.getPath());
Node subNode = subRes.adaptTo(Node.class);
if (null != subNode) {
Calendar subAssetExpiryTime = DamUtil.getExpiryTime(each);
if (null != subAssetExpiryTime && subAssetExpiryTime.before(now)) {
isSubAssetExpired = subAssetExpiryTime.before(now);
break;
}
}
}
}
}
return isSubAssetExpired;
}
/**
* Returns the single property value from the given node n
with
* name
. If there is no single-valued property for the given
* name
, then the defaultValue
is returned.
*
* @param n a node.
* @param name a property name.
* @param defaultValue the default value.
* @return the value for the given property name or the default value.
* @throws RepositoryException if value cannot be retrieved
*/
public static String getValue(Node n, String name, String defaultValue)
throws RepositoryException {
if (n == null) {
return defaultValue;
}
try {
Property p = n.getProperty(name);
if (!p.isMultiple()) {
return p.getString();
} else {
/*
* CQ5-13581 Multi value dc:title cause Title not to show up
* in UI.
*/
Value[] values = p.getValues();
String val = "";
boolean first = true;
for (Value a : values) {
if (!first) {
val += ", ";
} else {
first = false;
}
val += a.getString();
}
return val;
}
} catch (PathNotFoundException e) {
// property does not exist
}
return defaultValue;
}
/**
* To check weather asset falls under Image category.
* @param asset
* @return True if asset is of type Image.
*/
public static boolean isImage(Asset asset){
return IMG_MIME_TYPE.contains(asset.getMimeType());
}
/**
* To check weather asset falls under Video category.
* @param asset
* @return True if asset is of type video.
*/
public static boolean isVideo(final Asset asset) {
//CQ-3440 mimetype not extracted for certain formats
String errantTypes[] = {"mpv" ,"m2ts" , "m2t" , "m2p" , "vob" ,"ts", "webm", "mkv" };
List errantList = Arrays.asList(errantTypes);
return VID_MIME_TYPE.contains(asset.getMimeType()) ||
(asset.getMimeType()==null && errantList.contains(StringUtils.substringAfterLast(asset.getName(), ".").toLowerCase()));
}
/**
* Checks if given resource represent a smart collection
* @param resource an instance of {@link Resource}
* @return true
if resource
represents a smart collection
* false
if resource
does not represents a smart collection
*/
public static boolean isSmartCollection(final Resource resource) {
return resource.isResourceType(DamConstants.SMART_COLLECTION_SLING_RES_TYPE);
}
/**
* Get a specific Processing profile which may be applied to an asset
* @param asset The asset we get from payload of DamUpdateAsset Workflow
* @param profileType The type of profile to get (metadata/video/image)
* @param session To retrieve nodes from JCR
* @return {Node} the Processing Profile, null if not found
*/
public static Node getApplicableProfile(final Asset asset, final String profileType, final Session session) {
try {
Node assetNode = asset.adaptTo(Node.class);
Node parentNode;
String path = "";
if (null != assetNode) {
parentNode = assetNode.getParent();
while (!parentNode.getPath().equals("/content")) {
if (!parentNode.getPrimaryNodeType().getName().equals(DamConstants.NT_DAM_ASSET)
&& parentNode.hasProperty(JcrConstants.JCR_CONTENT + "/" + profileType)) {
path = parentNode.getProperty(JcrConstants.JCR_CONTENT + "/" + profileType).getString();
if (session.nodeExists(path)) {
return session.getNode(path);
}
}
parentNode = parentNode.getParent();
}
}
} catch (RepositoryException e) {
log.error("Unable to retrieve applicable profile", e);
}
return null;
}
/**
* Processing Profile overview has been removed. Now individual PPs are applied to folders.
* return null
* use @getApplicableProfile
*/
@Deprecated
public static String getAppliedProcessingProfilePath(final Asset asset) {
return null;
}
/**
* Returns an iterator to all the assets contained in or represented by the resource.
* If resource is a folder, then all its folders are navigated recursively and assets are listed
* If a resource is {@link ResourceCollection}, then all its member resources are consulted and navigated recursively if any of the member
* represent folder or {@link ResourceCollection}.
* If the resource represents an asset itself, an iterator of single item i.e. Collections.singletonList(res.adaptTo(Asset.class)).iterator();
* @param res a sling {@link Resource}
* @return an {@link Iterator} of {@link Asset}
*/
public static Iterator getAssets(Resource res) {
Asset asset = res.adaptTo(Asset.class);
if (asset == null) {
return new FolderAssetIterator(res);
} else {
return Collections.singletonList(asset).iterator();
}
}
public static boolean checkforAIFile(Asset asset) {
InputStream in;
if (asset != null && asset.getOriginal() != null) {
in = asset.getOriginal().getStream();
PushbackInputStream pin = new PushbackInputStream(in, MAGIC_SIZE);
byte[] data = new byte[MAGIC_SIZE];
int len;
try {
// prefetch some bytes to find correct handler
if ((len = pin.read(data)) <= 0) {
// no content
return false;
}
pin.unread(data, 0, len);
// check if it is an isAIFile with "application/postscript" as
// mimetype
byte[] pdfMarker = { '%', 'P', 'D', 'F', '-' };
int size = 1024;
if (size > len) size = len;
byte[] header = new byte[size];
System.arraycopy(data, 0, header, 0, size);
long result = Utility.KMPFindFirst(pdfMarker,
Utility.ComputeKMPNextArray(pdfMarker), header);
return (result >= 0);
} catch (IOException e) {
log.warn("I/O error while getting metadata.", e);
}
}
return false;
}
public static Rendition getBestFitRendition(int width,
List renditions) {
PrefixRenditionPicker prefixPicker = new PrefixRenditionPicker(
DamConstants.PREFIX_ASSET_THUMBNAIL + "." + width);
Rendition bestFitRendition = prefixPicker.getRendition(renditions.iterator());
if(bestFitRendition == null) {
prefixPicker = new PrefixRenditionPicker(
DamConstants.PREFIX_ASSET_WEB + "." + width);
bestFitRendition = prefixPicker.getRendition(renditions.iterator());
}
if (bestFitRendition != null) {
return bestFitRendition;
}
DamUtil.WidthBasedRenditionComparator comp = new DamUtil.WidthBasedRenditionComparator();
Collections.sort(renditions, comp);
Iterator itr = renditions.iterator();
Rendition bestFit = null;
while (itr.hasNext()) {
Rendition rend = itr.next();
if (UIHelper.canRenderOnWeb(rend.getMimeType())) {
int w = UIHelper.getWidth(rend);
if (w <= width) {
bestFit = rend;
}
}
}
itr = renditions.iterator();
// if all renditions are larger then given width, find rendition closest to size;
if (bestFit == null) {
while (itr.hasNext()) {
Rendition rend = itr.next();
if (UIHelper.canRenderOnWeb(rend.getMimeType())) {
bestFit = rend;
break;
}
}
}
return bestFit;
}
/**
* getImageDimension : To get actual width and height of the rendition or image for proper UI rendering of thumbnails , earlier new Layer () API was being used which was inefficient.
**/
public static Dimension getImageDimension(InputStream is, String filename){
Dimension imageDimension = new Dimension(0,0);
try {
imageDimension = Imaging.getImageSize(is, filename);
}catch(ImageReadException ex){log.error("Error in getting image dimension for rendition : "+ filename, ex); return imageDimension; }
catch(IOException ex){log.error("Error in getting image dimension for rendition : "+ filename, ex); return imageDimension; }
return imageDimension;
}
public static boolean expiryStatus (Asset asset) {
return false;
}
public static List getReferencedSubAssets (Resource resource) {
List refAssets = new ArrayList();
try {
Node node = resource.adaptTo(Node.class);
if (node == null || !node.hasProperty("jcr:content/related/links/sling:members/sling:resources")) {
return refAssets;
}
Property prop = resource.adaptTo(Node.class).getProperty("jcr:content/related/links/sling:members/sling:resources");
if (null != prop) {
Value [] values = prop.getValues();
for (Value each : values) {
Resource resEach = resource.getResourceResolver().getResource(each.getString());
if (null != resEach) {
Asset refAsset = resEach.adaptTo(Asset.class);
if (null != refAsset) {
refAssets.add(refAsset);
}
}
}
}
} catch (RepositoryException e) {
log.error("Error in getting referenced sub assets", e);
return refAssets;
}
return refAssets;
}
public static Collection getSubAssets (Resource resource) {
Collection assets = new LinkedList();
if (null != resource) {
Asset asset = resource.adaptTo(Asset.class);
if (null != asset) {
assets = asset.getSubAssets();
}
}
return assets;
}
public static Collection getRefererAssets (ResourceResolver resolver, String path) {
String root = "/jcr:root" + DamConstants.MOUNTPOINT_ASSETS;
String sub = "[jcr:content/related/links/sling:members/*/@dam:resolvedPath='%s']";
String query = String.format("%s//*" + sub, root, path);
log.debug("Find Referer Query:{0}", query);
Iterator iter = resolver.findResources(query, Query.XPATH);
List assets = new ArrayList();
while (iter.hasNext()) {
Resource res = iter.next();
Asset asset = null;
if (null != res) {
asset = res.adaptTo(Asset.class);
}
if (null != asset) {
assets.add(asset);
} else {
Node node = res.adaptTo(Node.class);
try {
if (node.hasProperty("dam:resolvedPath")) {
String assetPath = node.getProperty("dam:resolvedPath").getString();
Resource res1 = resolver.getResource(assetPath);
if (null != res1) {
asset = res1.adaptTo(Asset.class);
if (null != asset) {
assets.add(asset);
}
}
}
} catch (RepositoryException e) {
log.error("", e);
}
}
}
return assets;
}
public static Calendar getExpiryTime(Asset asset) {
if(asset == null){return null;}
String value = asset.getMetadataValueFromJcr("prism:expirationDate");
if (StringUtils.isNotEmpty(value)) {
Date date = DateParser.parseDate(value);
if (date != null) {
Calendar result = Calendar.getInstance();
result.setTime(date);
return result;
}
}
return null;
}
public static Asset getParentAsset (Resource resource) {
if (null != resource && isSubAsset(resource)) {
return resource.getParent().getParent().adaptTo(Asset.class);
} else {
if (null == resource) {
log.error("Resource NULL.");
} else {
log.error("Resource {0} is not a sub-asset", resource.getPath());
}
return null;
}
}
/**
* Checks if the asset is valid. It is valid if it has content and if the
* on-/off time range spans the current time.
* @return true
if the page is valid; false
* otherwise.
*/
public static boolean isValid(Asset asset) throws RepositoryException {
return isValid(asset.adaptTo(Node.class));
}
/**
* Obtain Tenant Asset's root for specified ResourceResolver
* @return the tenant root-path
*/
public static String getTenantAssetsRoot(ResourceResolver resolver) {
User user = resolver.adaptTo(User.class);
String mountPoint = MOUNTPOINT_ASSETS;
if (user != null && !user.isSystemUser()) { // added a explicit check to
// avoid adapting
// system-user-resolver to
// Tenant, as it generates a
// NPE in log file.
Tenant tenant = resolver.adaptTo(Tenant.class);
if (tenant != null) {
mountPoint = (String) tenant.getProperty(DAM_ASSETS_ROOT);
}
}
return mountPoint;
}
/**
* Obtain Tenant Asset's root for specified asset path and ResourceResolver
* This returns the tenant for the session associated with the resource resolver,
* not the tenant associated with the asset if provided assetPath
* can't be resolved to an Asset
* @return the tenant root-path
*/
public static String getTenantAssetsRoot(ResourceResolver resolver, String assetPath) {
Resource assetResource = resolver.getResource(assetPath);
if (assetResource == null) {
return MOUNTPOINT_ASSETS;
}
Tenant tenant = assetResource.adaptTo(Tenant.class);
if (tenant == null) {
return MOUNTPOINT_ASSETS;
} else {
return (String) tenant.getProperty(DAM_ASSETS_ROOT);
}
}
/**
* Obtain Tenant Asset's root for specified Sling resource
* @return the tenant root-path
*/
public static String getTenantAssetsRoot(Resource resource) {
if (resource == null) {
return MOUNTPOINT_ASSETS;
}
Tenant tenant = resource.adaptTo(Tenant.class);
if (tenant == null) {
return MOUNTPOINT_ASSETS;
} else {
return (String) tenant.getProperty(DAM_ASSETS_ROOT);
}
}
/**
* Obtain Asset
provided the jcr:uuid
* @return the Asset
, or null if asset with specified ID wasn't found
*
* @throws RepositoryException
*/
public static Asset getAssetFromID(ResourceResolver resolver, String id) throws RepositoryException {
try {
Node assetNode = resolver.adaptTo(Session.class).getNodeByIdentifier(id);
return resolver.getResource(assetNode.getPath()).adaptTo(Asset.class);
} catch (ItemNotFoundException ign) {
// ignore
return null;
} catch (IllegalArgumentException ign) {
// may happen for non-UUID "IDs" being supplied for lookup. ignore
return null;
}
}
/**
* Obtain Asset's path relative to specified Asset's root
* @return Asset's Relative Path (see {@link #DamConstants.DAM_ASSET_RELATIVE_PATH}
*/
public static String findRelativePathOfAssetNode (Node assetNode, String assetsRoot)
throws RepositoryException {
String assetAbsPath = assetNode.getPath();
int idx = -1;
if (0 <= (idx = assetAbsPath.indexOf(assetsRoot))) {
idx += assetsRoot.length();
}
return assetAbsPath.substring(idx + 1);
}
/**
* Checks if the asset is valid. It is valid if it has content and if the
* on-/off time range spans the current time.
* @return true
if the page is valid; false
* otherwise.
*/
private static boolean isValid(Node assetNode) throws RepositoryException {
return timeUntilValid(assetNode) == 0;
}
/**
* Returns the number of milliseconds when this asset gets valid. If the
* asset is already valid, 0
is returned. If the page is out
* dated, i.e. the offTime is in the past, a negative number is returned. If
* this page has no content {@link Long#MIN_VALUE} is returned.
* @return milliseconds until page gets valid.
*/
private static long timeUntilValid(Node assetNode) throws RepositoryException {
if (!hasContent(assetNode)) {
return Long.MIN_VALUE;
}
Calendar onTime = getOnTime(assetNode);
Calendar offTime = getOffTime(assetNode);
if (onTime == null && offTime == null) {
return 0;
}
long now = System.currentTimeMillis();
long timeUntilOn = onTime == null ? 0 : onTime.getTimeInMillis() - now;
if (timeUntilOn > 0) {
return timeUntilOn;
}
long timeUntilOff = offTime == null ? 0 : offTime.getTimeInMillis()
- now;
if (timeUntilOff < 0) {
return timeUntilOff;
}
return 0;
}
/**
* Checks if the asset has content attached.
* @return true
if the asset has content; false
* otherwise.
*/
private static boolean hasContent(Node assetNode) throws RepositoryException {
return assetNode.hasNode(JcrConstants.JCR_CONTENT);
}
/**
* Returns the onTime
of the asset. The onTime defines after
* which time it is valid. If no onTime is specified null
is
* returned and the onTime is not respected in the {@link #isValid()}
* calculation.
* @return onTime or null
*/
private static Calendar getOnTime(Node assetNode) throws RepositoryException {
if (hasContent(assetNode)
&& assetNode.getNode(JcrConstants.JCR_CONTENT).hasProperty(
DamConstants.PN_ON_TIME)) {
return assetNode.getNode(JcrConstants.JCR_CONTENT).getProperty(
DamConstants.PN_ON_TIME).getDate();
}
return null;
}
/**
* Returns the offTime
of the asset. The offTime defines before
* which time it is valid. If no offTime is specified null
is
* returned and the offTime is not respected in the {@link #isValid()}
* calculation.
* @return offTime or null
*/
private static Calendar getOffTime(Node assetNode) throws RepositoryException {
if (hasContent(assetNode)
&& assetNode.getNode(JcrConstants.JCR_CONTENT).hasProperty(
DamConstants.PN_OFF_TIME)) {
return assetNode.getNode(JcrConstants.JCR_CONTENT).getProperty(
DamConstants.PN_OFF_TIME).getDate();
}
return null;
}
/**
* This method searches for the property in the provided contentPath
* resource. Moves up the repository path until finds the property on the
* node. If not found or can't convert the found value to given type,
* returns null
*
* @param property
* the property user is looking for.
* @param resource
* the resource representing the path where the property has to
* be searched
* @param type
* The class of the type
* @return the value configured on the node hierarchy. null if property not
* found on the path hierarchy
*/
private static T getInheritedProperty(String property, Resource resource, Class type) {
if (null == type) {
log.debug("type argument can't be null");
return null;
}
if (StringUtils.isBlank(property)) {
log.debug("property name can't be empty");
return null;
}
if (null == resource) {
log.debug("content resource could not be null");
return null;
}
T value = null;
while (null != resource) {
ValueMap propertiesMap = resource.adaptTo(ValueMap.class);
if (null != propertiesMap && propertiesMap.containsKey(property)) {
value = propertiesMap.get(property, type);
break;
}
resource = resource.getParent();
}
if (null == value) {
if (null == resource) {
log.debug("property {} not found on the content path", property);
} else {
log.debug("property value retrived could not be converted to {}", type.getName());
}
return null;
}
return value;
}
/**
* This method searches for the property in the provided contentPath
* resource. Moves up the repository path until finds the property on the
* node. Tries to convert the found value to type of default value. If
* can't, returns the defaultValue
*
* @param property
* the property user is looking for.
* @param resource
* the resource representing the path where the property has to
* be searched
* @param defaultValue
* @return the value configured on the node hierarchy converted to type of
* default value. defaultValue if property not found on the path
* hierarchy
*/
public static T getInheritedProperty(String property, Resource resource, T defaultValue) {
if (null == defaultValue) {
log.debug("defaultValue argument cant be null");
return null;
}
@SuppressWarnings("unchecked")
T value = DamUtil.getInheritedProperty(property, resource, (Class) defaultValue.getClass());
if (null != value) {
return value;
}
return defaultValue;
}
/**
* This function determines if an asset has its DamConstants.DAM_ASSET_STATE
property is set to
* DamConstants.DAM_ASSET_STATE_PROCESSING
. Presently this returns true only if in DAM update
* asset workflow.
*
* @param resource
* the resource to check
* @return
* true if DamConstants.DAM_ASSET_STATE
property is set to DamConstants.DAM_ASSET_STATE_PROCESSING
* false otherwise
**/
public static boolean isInRunningWorkflow(Resource resource) {
boolean retVal = false;
try {
Resource jcrContent = resource.getResourceResolver().getResource(resource.getPath() + "/" + JCR_CONTENT);
ValueMap properties = jcrContent.getValueMap();
if (properties.containsKey(DamConstants.DAM_ASSET_STATE) && properties.get(DamConstants.DAM_ASSET_STATE).equals(DamConstants.DAM_ASSET_STATE_PROCESSING)) {
retVal = true;
}
} catch (Exception e) {
} finally {
return retVal;
}
}
private static class WidthBasedRenditionComparator implements Comparator {
public int compare(Rendition r1, Rendition r2) {
int w1 = UIHelper.getWidth(r1);
int w2 = UIHelper.getWidth(r2);
if (w1 < w2) {
return -1;
} else if (w1 == w2) {
return 0;
} else {
return 1;
}
}
}
/**
* A helper class that iterates recursively all child resources of a parent resource (folder or collection) that are asset.
*/
private static class FolderAssetIterator implements Iterator {
private Resource parentResource;
private Iterator it = null;
private List parentNodes = new ArrayList();
private Asset next = null;
private Iterator getChildren(Resource res) {
ResourceCollection rc = res.adaptTo(ResourceCollection.class);
if (rc != null) {
return rc.getResources();
}
return res.listChildren();
}
public FolderAssetIterator(Resource resource) {
this.parentResource = resource;
it = getChildren(this.parentResource);
next = getNext();
}
private Asset getNext() {
while (!it.hasNext() && !parentNodes.isEmpty()) {
it = getChildren(parentNodes.remove(0));
}
while (it.hasNext()) {
Resource member = it.next();
Node n = member.adaptTo(Node.class);
try {
if (n.isNodeType(NT_DAM_ASSET)) {
return member.adaptTo(Asset.class);
} else if (n.isNodeType(JcrConstants.NT_FOLDER) || member.adaptTo(ResourceCollection.class) != null) {
parentNodes.add(member);
}
} catch (RepositoryException e) {
log.error("unexpected exception ", e);
//try the next one
}
}
if (!parentNodes.isEmpty()) {
return getNext();
}
return null;
}
public boolean hasNext() {
return (next != null);
}
public Asset next() {
Asset toReturn = next;
next = getNext();
return toReturn;
}
public void remove() {
throw new UnsupportedOperationException("remove not allowed for asset iterator on folder listing");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy