TaskEMailNotificationService.java 14.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.taskmanagement.Task
 *  com.adobe.granite.taskmanagement.TaskEvent
 *  com.adobe.granite.taskmanagement.TaskEventType
 *  com.adobe.granite.taskmanagement.TaskManager
 *  com.adobe.granite.taskmanagement.TaskManagerException
 *  com.day.cq.mailer.MailService
 *  javax.jcr.Session
 *  org.apache.commons.lang.StringUtils
 *  org.apache.commons.mail.Email
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.ReferenceCardinality
 *  org.apache.felix.scr.annotations.ReferencePolicy
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.api.security.user.Authorizable
 *  org.apache.jackrabbit.api.security.user.UserManager
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.i18n.ResourceBundleProvider
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.osgi.service.component.ComponentContext
 *  org.osgi.service.event.Event
 *  org.osgi.service.event.EventHandler
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.workflow.impl.email;

import com.adobe.granite.taskmanagement.Task;
import com.adobe.granite.taskmanagement.TaskEvent;
import com.adobe.granite.taskmanagement.TaskEventType;
import com.adobe.granite.taskmanagement.TaskManager;
import com.adobe.granite.taskmanagement.TaskManagerException;
import com.day.cq.mailer.MailService;
import com.day.cq.workflow.impl.ServiceLoginUtil;
import com.day.cq.workflow.impl.email.EMailBuilder;
import com.day.cq.workflow.impl.email.Notification;
import com.day.cq.workflow.impl.email.NotificationHelper;
import com.day.cq.workflow.impl.email.TaskNotificationImpl;
import com.day.cq.workflow.impl.email.Template;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.jcr.Session;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.mail.Email;
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.Service;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.i18n.ResourceBundleProvider;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(immediate=1, label="Task Email Notification Service", metatype=1, description="Listens to task events and triggers email notifications.")
@Service(value={EventHandler.class})
@Properties(value={@Property(name="event.topics", value={"com/adobe/granite/taskmanagement/event"}, propertyPrivate=1), @Property(name="event.filter", value={"(!(event.application=*))"}, propertyPrivate=1)})
public class TaskEMailNotificationService
implements EventHandler {
    private static final Logger log = LoggerFactory.getLogger(TaskEMailNotificationService.class);
    @Property(value={"http://localhost:4502"}, label="Host URL Prefix", description="Used to prefix links to pages in the notification emails")
    private static final String NOTIFICATION_HOST_PREFIX = "host.prefix";
    @Property(boolValue={1}, label="Notify on Update", description="Enables notifications on task updates")
    private static final String NOTIFYONUPDATE = "notify.onupdate";
    @Property(boolValue={1}, label="Notify on Complete", description="Enables notifications on task completion")
    private static final String NOTIFYONCOMPLETE = "notify.oncomplete";
    private static final String DO_NOTIFY = "sendEmailNotification";
    private static final String TASK_CREATED_TEMPLATE_ROOT_LOCATION = "/etc/workflow/notification/email/tasks/created";
    private static final String TASK_SAVED_TEMPLATE_ROOT_LOCATION = "/etc/workflow/notification/email/tasks/saved";
    private static final String TASK_COMPLETED_TEMPLATE_ROOT_LOCATION = "/etc/workflow/notification/email/tasks/completed";
    private static final String TASK_EMAIL_NOTIFICATION_STOP = "TASK_EMAIL_NOTIFICATION_STOP";
    @Reference
    protected SlingRepository repository = null;
    @Reference
    private ResourceResolverFactory resolverFactory = null;
    @Reference(cardinality=ReferenceCardinality.MANDATORY_UNARY, policy=ReferencePolicy.STATIC)
    protected MailService mailService = null;
    @Reference
    protected ResourceBundleProvider resourceBundleProvider = null;
    private final BlockingQueue<TaskEvent> queue = new LinkedBlockingQueue<TaskEvent>();
    private EventProcessor processor;
    private String hostPrefix;
    private final Map<String, EMailBuilder> builders = new HashMap<String, EMailBuilder>();
    private boolean notifyOnUpdate;
    private boolean notifyOnComplete;

    public void handleEvent(Event event) {
        String topic = event.getTopic();
        if ("com/adobe/granite/taskmanagement/event".equals(topic)) {
            try {
                this.queue.put((TaskEvent)event);
                if (log.isDebugEnabled()) {
                    log.debug("handleEvent: put event [{}] in queue, size now [{}]", (Object)((TaskEvent)event).getEventType(), (Object)this.queue.size());
                }
            }
            catch (InterruptedException e) {}
        } else {
            log.debug("skipping non-task event: {}", (Object)event.toString());
        }
    }

    private boolean doNotifyOnEvent(TaskEvent taskEvent) {
        switch (taskEvent.getEventType()) {
            case TASK_CREATED: {
                return true;
            }
            case TASK_SAVED: {
                return this.notifyOnUpdate;
            }
            case TASK_COMPLETED: {
                return this.notifyOnComplete;
            }
        }
        return false;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void sendNotification(TaskEvent event) {
        TaskEventType taskEventType = (TaskEventType)event.getProperty("EventType");
        ResourceResolver repoResolver = null;
        ResourceResolver userResolver = null;
        try {
            repoResolver = ServiceLoginUtil.createRepositoryReaderResolver(this.resolverFactory);
            TaskManager taskManager = (TaskManager)repoResolver.adaptTo(TaskManager.class);
            String taskId = (String)event.getProperty("TaskId");
            Task task = taskManager.getTask(taskId);
            String notifyProperty = (String)task.getProperty("sendEmailNotification");
            if (!StringUtils.isBlank((String)notifyProperty) && Boolean.parseBoolean(notifyProperty)) {
                String userGroupId = task.getCurrentAssignee();
                userResolver = ServiceLoginUtil.createWorkflowUserReaderResolver(this.resolverFactory);
                Set<Authorizable> users = NotificationHelper.getParticipants(userGroupId, userResolver);
                String creatorId = task.getCreatedBy();
                users.addAll(NotificationHelper.getParticipants(creatorId, userResolver));
                for (Authorizable user : users) {
                    TaskNotificationImpl notification = new TaskNotificationImpl(task, event, repoResolver);
                    notification.load(this, user);
                    log.debug("Created and loaded notification for {}", (Object)event);
                    EMailBuilder builder = this.builders.get(taskEventType.name());
                    if (builder != null) {
                        try {
                            Email email = builder.build(notification, userResolver);
                            if (null != email) {
                                this.mailService.sendEmail(email);
                                continue;
                            }
                            log.error("could not send email, notificator did not deliver message: [{}]", (Object)notification);
                        }
                        catch (Throwable e) {
                            log.error("error while sending email for {}:", (Object)task.getId(), (Object)e);
                        }
                        continue;
                    }
                    log.debug("could not find suitable task notifier for type [{}] - [{}]", (Object)taskEventType, (Object)task);
                }
            }
        }
        catch (TaskManagerException e) {
            log.error("Unable to retrieve task for event: {}. aborting", (Object)event, (Object)e);
        }
        finally {
            if (repoResolver != null && repoResolver.isLive()) {
                repoResolver.close();
            }
            if (userResolver != null && userResolver.isLive()) {
                userResolver.close();
            }
        }
    }

    public String getHostPrefix() {
        return this.hostPrefix;
    }

    public String getUserLanguage(String userId) {
        return NotificationHelper.getUserLanguage(this.repository, this.resolverFactory, userId);
    }

    public ResourceBundle getUserResourceBundle(String language) {
        return this.resourceBundleProvider.getResourceBundle(new Locale(language));
    }

    private UserManager getUserManager(ResourceResolver userResolver) {
        UserManager um = null;
        if (userResolver != null) {
            um = (UserManager)userResolver.adaptTo(UserManager.class);
        }
        return um;
    }

    private ResourceResolver getResourceResolver(Session session) {
        ResourceResolver resolver = null;
        try {
            resolver = this.resolverFactory.getResourceResolver(Collections.singletonMap("user.jcr.session", session));
        }
        catch (LoginException e) {
            log.error("Unable to get resource resolver.", (Throwable)e);
        }
        return resolver;
    }

    private Session getWorkflowServiceSession() {
        return ServiceLoginUtil.createWorkflowServiceSession(this.repository);
    }

    protected void activate(ComponentContext context) {
        Dictionary properties = context.getProperties();
        this.hostPrefix = (String)properties.get("host.prefix");
        this.notifyOnUpdate = (Boolean)properties.get("notify.onupdate");
        this.notifyOnComplete = (Boolean)properties.get("notify.oncomplete");
        Session session = this.getWorkflowServiceSession();
        if (session != null) {
            this.builders.put(TaskEventType.TASK_CREATED.name(), new Template("/etc/workflow/notification/email/tasks/created", session));
            this.builders.put(TaskEventType.TASK_SAVED.name(), new Template("/etc/workflow/notification/email/tasks/saved", session));
            this.builders.put(TaskEventType.TASK_COMPLETED.name(), new Template("/etc/workflow/notification/email/tasks/completed", session));
        } else {
            log.error("Unable to load email templates.  Only default template will be used.");
        }
        if (session != null && session.isLive()) {
            session.logout();
        }
        this.processor = new EventProcessor();
        Thread thread = new Thread((Runnable)this.processor, this.getClass().getSimpleName() + "-Processor");
        thread.setDaemon(true);
        thread.start();
    }

    protected void deactivate(ComponentContext context) {
        this.processor.stop();
        Hashtable<String, Boolean> props = new Hashtable<String, Boolean>();
        props.put("TASK_EMAIL_NOTIFICATION_STOP", true);
        this.queue.offer(new TaskEvent(props));
    }

    protected void bindRepository(SlingRepository slingRepository) {
        this.repository = slingRepository;
    }

    protected void unbindRepository(SlingRepository slingRepository) {
        if (this.repository == slingRepository) {
            this.repository = null;
        }
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }

    protected void bindMailService(MailService mailService) {
        this.mailService = mailService;
    }

    protected void unbindMailService(MailService mailService) {
        if (this.mailService == mailService) {
            this.mailService = null;
        }
    }

    protected void bindResourceBundleProvider(ResourceBundleProvider resourceBundleProvider) {
        this.resourceBundleProvider = resourceBundleProvider;
    }

    protected void unbindResourceBundleProvider(ResourceBundleProvider resourceBundleProvider) {
        if (this.resourceBundleProvider == resourceBundleProvider) {
            this.resourceBundleProvider = null;
        }
    }

    private class EventProcessor
    implements Runnable {
        private volatile boolean isRunning;

        private EventProcessor() {
            this.isRunning = true;
        }

        public void stop() {
            this.isRunning = false;
        }

        @Override
        public void run() {
            log.debug("Processor started");
            while (this.isRunning) {
                try {
                    TaskEvent event;
                    if (log.isDebugEnabled()) {
                        log.debug("taking next event from queue - [{}] remaining", (Object)TaskEMailNotificationService.this.queue.size());
                    }
                    if ((event = (TaskEvent)TaskEMailNotificationService.this.queue.take()).getProperty("TASK_EMAIL_NOTIFICATION_STOP") != null) {
                        log.debug("stop event, get out");
                        break;
                    }
                    if (TaskEMailNotificationService.this.doNotifyOnEvent(event)) {
                        log.debug("sending notification for: {}", event.getProperty("EventType"));
                        TaskEMailNotificationService.this.sendNotification(event);
                        continue;
                    }
                    log.debug("ignoring notification for: {}", event.getProperty("EventType"));
                }
                catch (InterruptedException e) {}
            }
            log.debug("Processor done");
        }
    }

}