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

com.day.cq.dam.core.process.DownloadAssetProcess Maven / Gradle / Ivy

package com.day.cq.dam.core.process;

import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.day.cq.commons.Externalizer;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.jobs.AssetDownloadService;
import com.day.cq.dam.commons.process.AbstractAssetWorkflowProcess;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.metadata.MetaDataMap;

import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.ReferencePolicyOption;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.tenant.Tenant;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

/**
 * The DownloadAssetProcess will invoke the downloadasset service to process asset(s) download.
 */
@Component(metatype = false)
@Service
@Properties({
    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Download selected asset(s)."),
    @Property(name = "process.label", value = "Download Dam Asset")
})

public class DownloadAssetProcess extends AbstractAssetWorkflowProcess {
    /**
     * Logger instance for this class.
     */
    private static final Logger log = LoggerFactory.getLogger(DownloadAssetProcess.class);
    private static final String DOWNLOADASSETS = "downloadAssets";
    private static final String DOWNLOADRENDITIONS = "downloadRenditions";
    private static final String DOWNLOADSUBASSETS = "downloadSubassets";
    private static final String FLATSTRUCTURE = "flatStructure";
    private static final String S7EXPORTSETTINGS = "s7exportsettings";
    private static final String EMAILTO = "emailTo";
    private static final String CONTEXTPATH = "contextPath";
    private static final String SERVICE_USER_ID = "assetidhelper";

    @Reference(cardinality=ReferenceCardinality.MANDATORY_UNARY, policy=ReferencePolicy.STATIC)
    public AssetDownloadService assetDownloadService;

    @Reference(policyOption = ReferencePolicyOption.GREEDY)
    public Externalizer externalizer;
    
    @Reference
    public SlingRepository slingRepository;

    public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaData)
            throws WorkflowException {
        try {
            final Session session = workflowSession.getSession();
            final ResourceResolver rr = getResourceResolver(session);
            final String payload = workItem.getWorkflowData().getPayload().toString();
            final String srcPath = payload.split(".assetdownload.zip")[0];
            final MetaDataMap wfMetaDataMap = workItem.getWorkflowData().getMetaDataMap();
            final String contextPath = wfMetaDataMap.get(CONTEXTPATH, new String());
            // to exclude the "context-path" for "sling" to find and get the resource
            Resource resource = rr.getResource(srcPath.substring(contextPath.length()));
            
            // get the download job name and job options
            boolean downloadAssets = Boolean.parseBoolean(getValueFromPayload(DOWNLOADASSETS, payload));
            boolean downloadRenditions = Boolean.parseBoolean(getValueFromPayload(DOWNLOADRENDITIONS, payload));
            boolean downloadSubassets = Boolean.parseBoolean(getValueFromPayload(DOWNLOADSUBASSETS, payload));
            String s7exportsettings = getValueFromPayload(S7EXPORTSETTINGS, payload);
            if (StringUtils.isNotBlank(s7exportsettings)) {
                s7exportsettings = URLDecoder.decode(s7exportsettings, "UTF-8");
            }
            int idx = payload.indexOf("?");
            String downloadName = (idx == -1 ? "" : payload.substring(0, idx));
            downloadName = getDownloadName(downloadName);
            
            // get the download assets
            ArrayList paths = getAssetPath(payload);
            Set  downloadSet = new HashSet(); 
            if (paths != null && paths.size() > 0) {
                for (String path: paths) {
                    // no need to decode twice since it is done in getAssetPath(...) already
                    Resource res = rr.getResource(path);
                    if (res != null) {
                        downloadSet.add(res);
                    }
                }
            } else {
                downloadSet.add(resource);
            }
            
            // process download
            String emailRecipients = wfMetaDataMap.get(EMAILTO, new String());
            boolean flatStructure = Boolean.parseBoolean(getValueFromPayload(FLATSTRUCTURE, payload));
            String downloadUrl = assetDownloadService.assetDownload(
                    new AssetDownloadService.AssetDownloadParams(resource, downloadSet, downloadAssets, downloadRenditions, downloadSubassets, s7exportsettings, null, null, downloadName, emailRecipients, flatStructure, null));
            if (!StringUtils.isEmpty(downloadUrl)) {
                downloadUrl = getHostPrefix(workItem, rr, resource.getPath()) + downloadUrl;

                // store the downloadUrl as a WF metadata
                wfMetaDataMap.put(DamConstants.DOWNLOAD_URL, downloadUrl);
                
            } else{
                log.debug("downloadUrl is null or empty.");
            }
 
        } catch (Exception e) {
            log.error("execute: error while processing download asset; work item [{}]: ", workItem.getId(), e);
        }
    }
    
    private ArrayList getAssetPath(String arg) {
    	ArrayList paths = new ArrayList();
    	
    	try {
	        int beginIdx = arg.indexOf("path=");
	        while (beginIdx != -1) {
	            int endIdx = arg.indexOf("&", beginIdx + 1);
	            endIdx = (endIdx == -1 ? arg.length() : endIdx);
	            
	            //need to pre-process this, as the '%' character gets encoded, which breaks the loop in execute()
	            String path = arg.substring(beginIdx + "path+".length(), endIdx);
                paths.add(URLDecoder.decode(path, "UTF-8"));

	            beginIdx = arg.indexOf("path=", endIdx+1);
	        }
    	} catch (Exception e) {
    		log.error("unable to parse asset paths for download: " + arg, e);
    	}
    	
    	return paths;
    }
    
    private String getValueFromPayload(String key, String argment) {
        String value = null;
        // There might be s7dam imagepreset nested command settings, 
        // So not changing argments to an array by spliting "&"  
        int beginIdx = argment.indexOf(key); 
        if (beginIdx != -1 && validKeyParameter(key, argment.substring(beginIdx - 1, beginIdx + key.length() + 1))) {
            int endIdx = argment.indexOf("&", beginIdx);
            endIdx = (endIdx == -1 ? argment.length() : endIdx);
            value = (beginIdx == -1 ? "" : argment.substring(beginIdx + (key + "=").length(), endIdx));
        }
        return value;
    }
    
    private boolean validKeyParameter(String key, String argment) {
        // we want to make sure the parameter is valid and not an injected one 
        boolean valid = false;
        List params = Arrays.asList(argment.split("&|\\?|="));
        for (String param : params) {
            if (param.length() != 0) {
                valid = (param.equals(key));
            }
        }
        return valid;
    }
    
    private String getDownloadName(String pathInfo) {
        String name = pathInfo.substring(pathInfo.lastIndexOf("/") + 1, pathInfo.length());
        name = name.replaceAll("[\\[\\]\\/ :*|'\"S]", ""); // remove invalid chars to JCR
        name = (name.endsWith(".zip") ? name : name + ".zip");
        return name;
    }

    private String getHostPrefix(WorkItem workItem, ResourceResolver resolver, String resourcePath) {
        ResourceResolver resolverForExternalizer = getResolverForExternalizer(workItem, resolver);
        String externalizerHost = externalizer.externalLink(resolverForExternalizer, Externalizer.AUTHOR, "");
        if (externalizerHost != null && externalizerHost.endsWith("/")) {
            externalizerHost = externalizerHost.substring(0, externalizerHost.length()-1);
        }

        String tenantID = getTenantId(resolver, resourcePath);
        externalizerHost = adaptTenantIDToHostUrl(externalizerHost, tenantID);

        return externalizerHost;
    }

    private String adaptTenantIDToHostUrl(String hostPrefix, String tenantID) {
        try {
            URI uri = new URI(hostPrefix, false);
            String uriWithTenant = (!StringUtils.isEmpty(tenantID) ? tenantID + "." + uri.getHost() : uri.getHost());
            URI hostPrefixUri = new URI(uri.getScheme(), uri.getUserinfo(), uriWithTenant, uri.getPort(), uri.getPath());
            hostPrefix = hostPrefixUri.getURIReference();
        } catch (URIException e){
            log.error("Build uri failed with hostUrl [{}] and tenantID [{}]", new String[]{hostPrefix, tenantID}, e);
        }
        return hostPrefix;
    }

    private String getTenantId(ResourceResolver resolver, String downloadAssetsPath) {
        Tenant tenant = resolver.getResource(downloadAssetsPath).adaptTo(Tenant.class);
        return (tenant == null ? null : tenant.getId());
    }

    private ResourceResolver getResolverForExternalizer(WorkItem workItem, ResourceResolver workFlowResourceResolver) {
        final String initiator = workItem.getWorkflow().getInitiator();
        Session initiatorSession = getUserSession(initiator);
        ResourceResolver initiatorResolver = getResourceResolver(initiatorSession);
        if (initiatorResolver != null) {
            return initiatorResolver;
        }

        return workFlowResourceResolver;
    }

    private Session getUserSession(String userId) {
        final SimpleCredentials credentials = new SimpleCredentials(userId, new char[0]);
        try {
            return slingRepository.impersonateFromService(SERVICE_USER_ID, credentials, null);
        } catch (Exception e) {
            log.info("Impersonation of user '{}' failed", userId, e);
            return null;
        }
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy