ProjectTaskListServlet.java 16.5 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.security.user.UserPropertiesManager
 *  com.adobe.granite.security.user.UserPropertiesService
 *  com.adobe.granite.taskmanagement.Filter
 *  com.adobe.granite.taskmanagement.Task
 *  com.adobe.granite.taskmanagement.TaskManager
 *  com.adobe.granite.taskmanagement.TaskManagerException
 *  com.adobe.granite.workflow.WorkflowException
 *  com.adobe.granite.workflow.WorkflowSession
 *  com.adobe.granite.workflow.exec.Workflow
 *  com.adobe.granite.workflow.payload.PayloadInfoBuilderManager
 *  com.day.cq.commons.TidyJSONWriter
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Workspace
 *  javax.jcr.observation.EventIterator
 *  javax.jcr.observation.EventListener
 *  javax.jcr.observation.ObservationManager
 *  javax.servlet.Servlet
 *  javax.servlet.ServletException
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.api.observation.JackrabbitEventFilter
 *  org.apache.jackrabbit.api.observation.JackrabbitObservationManager
 *  org.apache.jackrabbit.api.security.user.UserManager
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.api.servlets.SlingSafeMethodsServlet
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.apache.sling.resourcemerger.api.ResourceMergerService
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.projects.impl.servlet;

import com.adobe.cq.projects.impl.servlet.ListItem;
import com.adobe.cq.projects.impl.servlet.TaskListItem;
import com.adobe.cq.projects.impl.servlet.WorkflowListItem;
import com.adobe.granite.security.user.UserPropertiesManager;
import com.adobe.granite.security.user.UserPropertiesService;
import com.adobe.granite.taskmanagement.Filter;
import com.adobe.granite.taskmanagement.Task;
import com.adobe.granite.taskmanagement.TaskManager;
import com.adobe.granite.taskmanagement.TaskManagerException;
import com.adobe.granite.workflow.WorkflowException;
import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.Workflow;
import com.adobe.granite.workflow.payload.PayloadInfoBuilderManager;
import com.day.cq.commons.TidyJSONWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
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.Service;
import org.apache.jackrabbit.api.observation.JackrabbitEventFilter;
import org.apache.jackrabbit.api.observation.JackrabbitObservationManager;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.resourcemerger.api.ResourceMergerService;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(name="com.adobe.cq.projects.ProjectTaskListServlet", immediate=1, label="ProjectTaskListServlet", metatype=0, description="Retrieve Project Tasks")
@Service(value={Servlet.class})
@Properties(value={@Property(name="sling.servlet.resourceTypes", value={"cq/core/content/projects/showtasks"}, propertyPrivate=1), @Property(name="sling.servlet.extensions", value={"json"}, propertyPrivate=1)})
public class ProjectTaskListServlet
extends SlingSafeMethodsServlet
implements EventListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(ProjectTaskListServlet.class);
    private static final String PROP_NAME_WFINSTANCE_ID = "wfInstanceId";
    private static final String TASK_TYPES_CONTENT_PATH = "/libs/cq/core/content/projects/tasktypes";
    private static final String OLD_TASK_TYPES_CONTENT_PATH = "/etc/projects/tasks/types";
    private static final String CUSTOM_TASK_TYPES_CONTENT_PATH = "/apps/cq/core/content/projects/tasktypes";
    private static final String PROJECTS_SERVICE = "projects-service";
    private static final String[] PATHS = new String[]{"/libs/cq/core/content/projects/tasktypes", "/etc/projects/tasks/types", "/apps/cq/core/content/projects/tasktypes"};
    @Reference
    SlingRepository slingRepository;
    @Reference
    ResourceMergerService resourceMerger;
    @Reference
    private ResourceResolverFactory rrf;
    @Reference
    private UserPropertiesService upService;
    private Map<String, String> taskRenderers;
    private Session projectsServiceSession;

    @Activate
    protected void activate(ComponentContext componentContext) throws Exception {
        this.projectsServiceSession = this.slingRepository.loginService("projects-service", null);
        if (this.projectsServiceSession != null) {
            this.getTaskRenderers();
            LOGGER.debug("Adding listener to track task type changes.");
            JackrabbitEventFilter filter = new JackrabbitEventFilter().setAbsPath("/libs/cq/core/content/projects/tasktypes").setEventTypes(63).setIsDeep(true).setNoLocal(true).setNoExternal(false).setAdditionalPaths(PATHS);
            JackrabbitObservationManager observationManager = (JackrabbitObservationManager)this.projectsServiceSession.getWorkspace().getObservationManager();
            observationManager.addEventListener((EventListener)this, filter);
        } else {
            LOGGER.error("Unable to log in projects service user.");
        }
    }

    @Deactivate
    protected void deactivate(ComponentContext context) {
        if (this.projectsServiceSession != null) {
            try {
                this.projectsServiceSession.getWorkspace().getObservationManager().removeEventListener((EventListener)this);
            }
            catch (RepositoryException e) {
                LOGGER.warn("Error while unregistering observation listener.", (Throwable)e);
            }
            this.projectsServiceSession.logout();
        }
    }

    private void getTaskRenderers() {
        LOGGER.debug("Building task type cache.");
        if (this.taskRenderers == null) {
            this.taskRenderers = new HashMap<String, String>();
            try {
                HashMap map = new HashMap();
                ResourceResolver resourceResolver = this.rrf.getServiceResourceResolver(Collections.singletonMap("sling.service.subservice", "projects-service"));
                Resource taskTypeConfig = this.resourceMerger.getMergedResource(resourceResolver.getResource("/libs/cq/core/content/projects/tasktypes"));
                this.readTaskTypes(taskTypeConfig);
                Resource oldLocation = resourceResolver.getResource("/etc/projects/tasks/types");
                if (oldLocation != null && oldLocation.getChildren().iterator().hasNext()) {
                    LOGGER.warn("Task type definitions detected under old location [{}].  These must be migrated to [/apps/cq/core/content/projects/tasktypes].", (Object)"/etc/projects/tasks/types");
                    this.readTaskTypes(oldLocation);
                }
            }
            catch (LoginException e) {
                LOGGER.warn("Error reading task type config from /libs/cq/core/content/projects/tasktypes", (Throwable)e);
            }
        }
    }

    private void readTaskTypes(Resource taskTypeConfig) {
        if (taskTypeConfig != null) {
            for (Resource ns : taskTypeConfig.getChildren()) {
                String namespace = ns.getName();
                if (namespace.startsWith("rep:")) continue;
                for (Resource taskType : ns.getChildren()) {
                    ValueMap taskTypeVM = (ValueMap)taskType.adaptTo(ValueMap.class);
                    String tt = namespace + ":" + (String)taskTypeVM.get("tasktype", String.class);
                    String url = (String)taskTypeVM.get("url", String.class);
                    if (this.taskRenderers.containsKey(tt)) continue;
                    LOGGER.debug("Adding task type: {}", (Object)tt);
                    this.taskRenderers.put(tt, url);
                }
            }
        }
    }

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        LOGGER.debug("In doGet");
        Map<String, String> renderers = this.taskRenderers;
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        int start = 0;
        String startParam = request.getParameter("start");
        if (startParam != null && !startParam.equals("")) {
            start = Integer.valueOf(startParam);
        }
        int limit = -1;
        String limitParam = request.getParameter("limit");
        if (limitParam != null && !limitParam.equals("")) {
            limit = Integer.valueOf(limitParam);
        }
        try {
            ResourceResolver resourceResolver = request.getResourceResolver();
            PayloadInfoBuilderManager payloadBuilder = (PayloadInfoBuilderManager)resourceResolver.adaptTo(PayloadInfoBuilderManager.class);
            UserManager usrMgr = (UserManager)resourceResolver.adaptTo(UserManager.class);
            UserPropertiesManager userPropertiesManager = this.upService.createUserPropertiesManager(resourceResolver);
            List<ListItem> orderedTaskList = this.loadTasks(request);
            TidyJSONWriter writer = new TidyJSONWriter((Writer)response.getWriter());
            writer.setTidy(true);
            writer.object();
            writer.key("results").value((long)this.countItems(orderedTaskList));
            writer.key("items").array();
            int currentIndex = 0;
            int totalItemsWritten = 0;
            for (ListItem listItem : orderedTaskList) {
                if (currentIndex >= start && totalItemsWritten < limit) {
                    ++totalItemsWritten;
                    listItem.write(writer, usrMgr, userPropertiesManager, resourceResolver, request, (HttpServletResponse)response, renderers);
                }
                ++currentIndex;
            }
            writer.endArray();
            writer.endObject();
        }
        catch (Exception e) {
            throw new ServletException("Retrieving the task list failed", (Throwable)e);
        }
    }

    private int countItems(List<ListItem> orderedTaskList) {
        int count = 0;
        if (orderedTaskList != null) {
            Iterator<ListItem> tlIt = orderedTaskList.iterator();
            while (tlIt.hasNext()) {
                ++count;
                ListItem item = tlIt.next();
                count += item.countSubItems();
            }
        }
        return count;
    }

    private List<ListItem> loadTasks(SlingHttpServletRequest request) throws TaskManagerException {
        Resource tasksNode;
        List<ListItem> collatedTasks = Collections.emptyList();
        String projectPath = request.getParameter("rootPath");
        ResourceResolver resourceResolver = request.getResourceResolver();
        Resource projectResource = resourceResolver.getResource(projectPath);
        Resource projectContent = projectResource.getChild("jcr:content");
        TaskManager taskManager = null;
        if (projectContent != null && (tasksNode = projectContent.getChild("tasks")) != null) {
            taskManager = (TaskManager)tasksNode.adaptTo(TaskManager.class);
        }
        if (taskManager != null) {
            WorkflowSession wfSession = (WorkflowSession)request.getResourceResolver().adaptTo(WorkflowSession.class);
            collatedTasks = this.collateTasks(wfSession, taskManager.getTasks(null, 0, -1));
        }
        return collatedTasks;
    }

    private List<ListItem> collateTasks(WorkflowSession wfSession, Iterator<Task> taskIterator) {
        HashMap<String, ListItem> itemMap = new HashMap<String, ListItem>();
        if (taskIterator != null) {
            while (taskIterator.hasNext()) {
                Task task = taskIterator.next();
                String mapId = (String)task.getProperty("wfInstanceId");
                ListItem item = null;
                if (mapId != null) {
                    item = (ListItem)itemMap.get(mapId);
                    if (item == null) {
                        Workflow workflow = null;
                        try {
                            workflow = wfSession.getWorkflow(mapId);
                            item = new WorkflowListItem(workflow);
                        }
                        catch (WorkflowException e) {
                            LOGGER.debug("Failed to load workflow for workflowInstanceId '{}'", (Object)mapId);
                            item = new WorkflowListItem(mapId);
                        }
                    }
                    WorkflowListItem wfListItem = (WorkflowListItem)item;
                    wfListItem.addTask(task);
                } else {
                    item = new TaskListItem(task);
                }
                itemMap.put(item.getMapId(), item);
            }
        }
        ArrayList<ListItem> result = new ArrayList<ListItem>(itemMap.values());
        Iterator resultIterator = result.iterator();
        while (resultIterator.hasNext()) {
            ((ListItem)resultIterator.next()).sortTasks();
        }
        Collections.sort(result, new Comparator<ListItem>(){

            @Override
            public int compare(ListItem lhs, ListItem rhs) {
                if (lhs != null) {
                    return lhs.compareDueDates(rhs);
                }
                if (rhs != null) {
                    return -1;
                }
                return 0;
            }
        });
        return result;
    }

    public void onEvent(EventIterator events) {
        LOGGER.debug("Received Observation event.  Rebuilding cache.");
        this.taskRenderers = null;
        this.getTaskRenderers();
    }

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

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

    protected void bindResourceMerger(ResourceMergerService resourceMergerService) {
        this.resourceMerger = resourceMergerService;
    }

    protected void unbindResourceMerger(ResourceMergerService resourceMergerService) {
        if (this.resourceMerger == resourceMergerService) {
            this.resourceMerger = null;
        }
    }

    protected void bindRrf(ResourceResolverFactory resourceResolverFactory) {
        this.rrf = resourceResolverFactory;
    }

    protected void unbindRrf(ResourceResolverFactory resourceResolverFactory) {
        if (this.rrf == resourceResolverFactory) {
            this.rrf = null;
        }
    }

    protected void bindUpService(UserPropertiesService userPropertiesService) {
        this.upService = userPropertiesService;
    }

    protected void unbindUpService(UserPropertiesService userPropertiesService) {
        if (this.upService == userPropertiesService) {
            this.upService = null;
        }
    }

}