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

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

There is a newer version: 6.5.21
Show newest version
package com.day.cq.dam.core.process;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.mail.Header;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
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.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.caconfig.resource.ConfigurationResourceResolver;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.tika.io.CountingInputStream;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.commons.Externalizer;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.commons.process.AbstractAssetWorkflowProcess;
import com.day.cq.dam.commons.util.DamUtil;
import com.day.cq.mailer.MessageGatewayService;
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;

/**
 * The SendDownloadAssetEmailProcess will send download asset email.
 */
@Component(metatype = false)
@Service
@Properties({
    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Send download asset email notification."),
    @Property(name = "process.label", value = "Send Download Asset Email Notification")
})

public class SendDownloadAssetEmailProcess extends AbstractAssetWorkflowProcess{

    private static final Logger log = LoggerFactory.getLogger(SendDownloadAssetEmailProcess.class);
    private static final String DEFAULT_CHARSET = "utf-8";
    private static final String EMAIL_TEMPLATE_LEGACY_BUCKET = "/etc";
    private static final String EMAIL_TEMPLATE_CACONFIG_BUCKET = "settings";
    private static final String SERVICE_USER_ID = "assetidhelper";

    @Reference(policy=ReferencePolicy.STATIC)
    private MessageGatewayService messageGatewayService;

    @Reference(policyOption = ReferencePolicyOption.GREEDY)
    private Externalizer externalizer;

    @Reference
    private ConfigurationResourceResolver configResolver;    

    @Reference
    private SlingRepository repository;
    
    public void execute(WorkItem workItem, WorkflowSession session, MetaDataMap metaData) 
            throws WorkflowException {
        MetaDataMap workflowMetaDataMap = workItem.getWorkflowData().getMetaDataMap();
        ResourceResolver resolver = getResourceResolver(session.getSession());
        
        // do not execute upon missing mail service. osgi component still needs to be available for UI
        // selection in workflow step configuration.
        if (messageGatewayService != null && (messageGatewayService.getGateway(HtmlEmail.class) != null)) { 
            try{
                ArrayList emailRecipients = getEmailRecipients(workflowMetaDataMap);
                if (workflowMetaDataMap != null) {
                	String downloadUrl = (workflowMetaDataMap.containsKey(DamConstants.DOWNLOAD_URL) ? workflowMetaDataMap.get(DamConstants.DOWNLOAD_URL).toString() : null);

                    if (emailRecipients != null && emailRecipients.size() != 0 && downloadUrl != null) {
                        String template = getEmailTemplate(metaData, resolver);

                        if (template != null) {
                            // get the string substitutors

                            String zipFileName = downloadUrl.substring(downloadUrl.lastIndexOf('/')+1);
                            Map valuesMap = new HashMap();
                            String hostPrefix = getHostPrefix(workItem, resolver);
                            valuesMap.put("host.prefix", hostPrefix);
                            valuesMap.put("zipFileName", zipFileName);
                            String encodedFileName = null;
                            try {
                                encodedFileName = URLEncoder.encode(zipFileName, "UTF-8");
                            } catch (UnsupportedEncodingException e) {
                                log.error( "Encode the file name failed before sending email in workflow", e);
                            }
                            valuesMap.put("downloadurl", downloadUrl.substring(0, downloadUrl.lastIndexOf('/')+1) + encodedFileName);
                            StrSubstitutor substitutor = new StrSubstitutor(valuesMap);
                            
                            final HtmlEmail email = createEmail(template, substitutor);
                            email.setTo( emailRecipients );
                            
                            messageGatewayService.getGateway(HtmlEmail.class).send(email);

                            log.info("Email was sent.");
                        } else {
                            log.warn("Did not send email. No email template defined");
                        }
                    } else {
                        log.warn("Did not send email. No recipient addresses or assets download URL available."); 
                    }
                } else {
                    log.warn("Did not send email. No workflow metadata is null.");
                }
            }
            catch (EmailException e) {
                e.printStackTrace();
                log.error( "Fatal error while sending email in workflow", e);
            }
        } else {
            log.warn("cannot send email, mail service unavailable. Please configure Gateway in OSGi Console");
        }
    } 
    
    private ArrayList getEmailRecipients(MetaDataMap workflowMetaDataMap) {
        ArrayList emailRecipients = null;
        String recipients = workflowMetaDataMap.get("emailTo", new String());
        try {
            recipients = URLDecoder.decode(recipients, "UTF-8");
            List recipientList = Arrays.asList(recipients.split(","));
            emailRecipients = new ArrayList();

            for (String recipient: recipientList) {
                if (!StringUtils.isEmpty(recipient))
                    emailRecipients.add(new InternetAddress(recipient));
            }
        } catch (UnsupportedEncodingException e){
            log.error("Cannot decode the recipient email address: " + e.getMessage());
        } catch (AddressException e){
            log.error("Cannot get the recipient email address: " + e.getMessage());
        }
        return emailRecipients;
    }
    
    private String getEmailTemplate(MetaDataMap workflowMetaDataMap, ResourceResolver resolver) {
        String template = workflowMetaDataMap.get("template", String.class);
        if (template == null) {
            // load mail template
            String templatePath = workflowMetaDataMap.get("templatePath", String.class);
            if (templatePath.startsWith("/")) {
                // absolute path specified, resolve using JCR session
                template = loadTemplate(resolver.adaptTo(Session.class), templatePath);
            } else {
                template = loadTemplate(resolver, templatePath);
            }
        }
        log.debug("Loaded template: {}", template);
        return template;
    }
    
    private HtmlEmail createEmail(final String template, final StrSubstitutor substitutor) {
        final HtmlEmail email = new HtmlEmail();
        try {
            // Note that substitutions must be called, because they are expected to be
            // US-ASCII only or specially encoded using MimeUtils class, but substitutions might introduce other chars,
            // like e.g. Japanese characters.
            // Further the CountingInputStream class does not seem to properly count when reading Japanese characters.
            final CountingInputStream in = new CountingInputStream(new ByteArrayInputStream(template.getBytes(DEFAULT_CHARSET)));
            final InternetHeaders iHdrs = new InternetHeaders(in);
            final Map hdrs = new HashMap();
            final Enumeration e = iHdrs.getAllHeaders();
            while (e.hasMoreElements()) {
                final Header hdr = (Header) e.nextElement();
                final String name = hdr.getName();
                log.debug("Header: {} = {}", name, hdr.getValue());
                hdrs.put(name, iHdrs.getHeader(name));
            }

            // use the counting stream reader to read the mail body
            String templateBody = template.substring(in.getCount());

            // create email
            email.setCharset(DEFAULT_CHARSET);
            
            // set subject
            final String[] ret = hdrs.remove("subject");
            final String subject = (ret == null ? "" : ret[0]);
            log.info("Email subject: " + subject);
            if (!StringUtils.isEmpty(subject)) {
                email.setSubject(substitutor.replace(subject));
            }

            // set message body
            templateBody = substitutor.replace(templateBody);
            log.debug("Substituted mail body: {}", templateBody);
            email.setMsg(templateBody);
            
            IOUtils.closeQuietly(in);
        } catch (Exception e){
            log.error("Create email: ", e.getMessage());
        }
        return email;
    }

    /**
     * Loads the mail templates from the repository.
     * @deprecated since 6.4. Reading content of email-templates given template-absolute-paths is
     * not supported.
     * @param path mail templates root path
     * @param session session
     * @return a reader to the template or null if not valid.
     */
    @Deprecated
    public String loadTemplate(final Session session, final String path) {
        InputStream is = null;
        try {
            log.warn("Reading content of email-templates given template-absolute-paths is deprecated");
            final Node content = session.getNode(path + "/" + JcrConstants.JCR_CONTENT);
            is = content.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
            final InputStreamReader r = new InputStreamReader(is, DEFAULT_CHARSET);
            final StringWriter w = new StringWriter();
            IOUtils.copy(r, w);
            return w.toString();
        } catch (final Exception e) {
            log.error("Error while loading mail template {}:{}", path, e.toString());
        } finally {
            IOUtils.closeQuietly(is);
        }
        return null;
    }

    private String loadTemplate(final ResourceResolver resolver, final String path) {
        InputStream is = null;
        try {
         // locate legacy templates first
            Resource resource = resolver.getResource(EMAIL_TEMPLATE_LEGACY_BUCKET + "/" + path);
            if (null == resource) { // no legacy
                Resource tenantAssetRootResource = resolver.getResource(DamUtil.getTenantAssetsRoot(resolver));
                resource = configResolver.getResource(tenantAssetRootResource, EMAIL_TEMPLATE_CACONFIG_BUCKET, path);
            }

            final Node content = resource.adaptTo(Node.class).getNode(JcrConstants.JCR_CONTENT);
            is = content.getProperty(JcrConstants.JCR_DATA).getBinary().getStream();
            final InputStreamReader r = new InputStreamReader(is, DEFAULT_CHARSET);
            final StringWriter w = new StringWriter();
            IOUtils.copy(r, w);
            return w.toString();
        } catch (final Exception e) {
            log.error("Error while loading mail template {}:{}", path, e.toString());
        } finally {
            IOUtils.closeQuietly(is);
        }
        return null;
    }

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

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