FormChooserServlet.java 13 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.PathInfo
 *  com.day.cq.commons.servlets.NonExistingResourceServlet
 *  com.day.cq.search.PredicateConverter
 *  com.day.cq.search.PredicateGroup
 *  com.day.cq.search.Query
 *  com.day.cq.search.QueryBuilder
 *  com.day.cq.search.result.Hit
 *  com.day.cq.search.result.SearchResult
 *  com.day.cq.wcm.api.components.IncludeOptions
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.servlet.RequestDispatcher
 *  javax.servlet.Servlet
 *  javax.servlet.ServletException
 *  javax.servlet.ServletRequest
 *  javax.servlet.ServletResponse
 *  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.Service
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.request.RequestDispatcherOptions
 *  org.apache.sling.api.request.RequestPathInfo
 *  org.apache.sling.api.resource.NonExistingResource
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.servlets.SlingAllMethodsServlet
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.wcm.foundation.forms.impl;

import com.day.cq.commons.PathInfo;
import com.day.cq.commons.servlets.NonExistingResourceServlet;
import com.day.cq.search.PredicateConverter;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;
import com.day.cq.wcm.api.components.IncludeOptions;
import com.day.cq.wcm.foundation.forms.FormResourceEdit;
import com.day.cq.wcm.foundation.forms.FormsHelper;
import com.day.cq.wcm.foundation.forms.impl.FormsHandlingRequest;
import java.io.IOException;
import java.util.ArrayList;
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.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.NonExistingResource;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=0)
@Service(value={Servlet.class, NonExistingResourceServlet.class})
@Properties(value={@Property(name="service.name", value={"CQ Form chooser servlet"}), @Property(name="service.description", value={"Renders the current resource(s) with a form"}), @Property(name="sling.servlet.resourceTypes", value={"sling/servlet/default"}), @Property(name="sling.servlet.selectors", value={"form"}), @Property(name="sling.servlet.methods", value={"GET", "POST"}), @Property(name="service.ranking", intValue={100})})
public class FormChooserServlet
extends SlingAllMethodsServlet
implements NonExistingResourceServlet {
    @Deprecated
    public static final String REQ_PARAM_PATH = "path";
    public static final String REQ_PARAM_QUERY = "query";
    public static final String PN_FORM_ALIAS = "cq:formAlias";
    public static final String PN_FORM_DEFAULT_RT = "cq:defaultFormFor";
    public static final String CONTENT_PATH = "/content";
    protected static final String SELECTOR = "form";
    protected static final String CREATE_SELECTOR = "create";
    protected static final String READ_ONLY_SELECTOR = "view";
    private static final Logger log = LoggerFactory.getLogger(FormChooserServlet.class);
    @Reference
    private QueryBuilder queryBuilder;

    public static boolean isNonExistingResource(Resource resource) {
        return "sling:nonexisting".equals(resource.getResourceType());
    }

    public static RequestPathInfo getPathInfo(SlingHttpServletRequest request) {
        if (FormChooserServlet.isNonExistingResource(request.getResource())) {
            return new PathInfo(request.getResource().getPath());
        }
        return request.getRequestPathInfo();
    }

    public static boolean hasSelector(RequestPathInfo pathInfo, String selector) {
        for (String s : pathInfo.getSelectors()) {
            if (!s.equals(selector)) continue;
            return true;
        }
        return false;
    }

    public boolean accepts(SlingHttpServletRequest request) {
        return FormChooserServlet.hasSelector(FormChooserServlet.getPathInfo(request), "form");
    }

    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        String formPath = this.findForm(request);
        if (formPath != null) {
            log.debug("using form: " + formPath);
            FormResourceEdit.setResources((ServletRequest)request, this.collectResources(request));
            if (this.isReadOnly(request)) {
                FormsHelper.setFormReadOnly(request);
            }
            request.setAttribute("browsermap.enabled", (Object)false);
            this.forward(formPath, request, response);
        } else {
            log.debug("no form found");
            response.sendError(404, "No form found");
        }
    }

    protected boolean isReadOnly(SlingHttpServletRequest request) {
        return FormChooserServlet.hasSelector(request.getRequestPathInfo(), "view");
    }

    protected String findForm(SlingHttpServletRequest request) {
        List<String> list;
        RequestPathInfo pathInfo = FormChooserServlet.getPathInfo(request);
        String suffix = pathInfo.getSuffix();
        if (suffix != null) {
            return suffix;
        }
        String[] selectors = pathInfo.getSelectors();
        String formAlias = null;
        if (selectors.length > 1) {
            for (String selector : selectors) {
                if (selector.equals("form") || selector.equals("create")) continue;
                formAlias = selector;
                break;
            }
        }
        if (formAlias != null && (list = this.search(null, "cq:formAlias", formAlias, request.getResourceResolver())).size() > 0) {
            return list.get(0);
        }
        list = this.search(null, "cq:defaultFormFor", request.getResource().getResourceType(), request.getResourceResolver());
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    protected void forward(String path, SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        RequestDispatcherOptions options = new RequestDispatcherOptions();
        options.setReplaceSelectors(null);
        options.setReplaceSuffix(null);
        if (path.endsWith(".html")) {
            path = path.substring(0, path.length() - ".html".length());
        }
        StringBuffer includePath = new StringBuffer(path);
        IncludeOptions.getOptions((ServletRequest)request, (boolean)true).forceSameContext(true);
        includePath.append("/jcr:content");
        for (String selector : request.getRequestPathInfo().getSelectors()) {
            if (selector.equals("form")) continue;
            includePath.append(".").append(selector);
        }
        includePath.append(".html");
        RequestDispatcher dispatcher = request.getRequestDispatcher(includePath.toString(), options);
        dispatcher.forward((ServletRequest)new FormsHandlingRequest(request), (ServletResponse)response);
    }

    protected List<String> search(String nodeType, String property, String value, ResourceResolver resolver) {
        ArrayList<String> result = new ArrayList<String>();
        StringBuilder buffer = new StringBuilder();
        if (nodeType != null) {
            buffer.append("//element(*, ").append(nodeType).append(")");
        } else {
            buffer.append("//*");
        }
        buffer.append("[@");
        buffer.append(property);
        buffer.append("='");
        buffer.append(value);
        buffer.append("']");
        log.debug("Query: {}", (Object)buffer.toString());
        Iterator iter = resolver.findResources(buffer.toString(), "xpath");
        while (iter.hasNext()) {
            result.add(((Resource)iter.next()).getPath());
        }
        Collections.sort(result, new SearchPathComparator(this.getFormSearchPath(resolver)));
        return result;
    }

    protected List<String> getFormSearchPath(ResourceResolver resolver) {
        ArrayList<String> searchPath = new ArrayList<String>();
        searchPath.add("/content");
        for (String path : resolver.getSearchPath()) {
            searchPath.add(path);
        }
        return searchPath;
    }

    protected List<Resource> collectResources(SlingHttpServletRequest request) {
        ArrayList<Resource> resources = new ArrayList<Resource>();
        if (FormChooserServlet.isNonExistingResource(request.getResource())) {
            String nonExistentPath = new PathInfo(request.getResource().getPath()).getResourcePath();
            resources.add((Resource)new NonExistingResource(request.getResourceResolver(), nonExistentPath));
            return resources;
        }
        if (FormChooserServlet.hasSelector(request.getRequestPathInfo(), "create")) {
            String path;
            resources.add((Resource)new NonExistingResource(request.getResourceResolver(), (path = request.getResource().getPath()).endsWith("/") ? path : path + "/"));
            return resources;
        }
        String[] paths = request.getParameterValues(":resource");
        ResourceResolver resolver = request.getResourceResolver();
        if (request.getParameter("query") != null) {
            log.debug("resources defined by query");
            HashMap map = new HashMap(request.getParameterMap());
            map.remove("query");
            Session session = (Session)resolver.adaptTo(Session.class);
            if (session != null) {
                Query query = this.queryBuilder.createQuery(PredicateConverter.createPredicates(map), session);
                SearchResult result = query.getResult();
                for (Hit hit : result.getHits()) {
                    try {
                        resources.add(hit.getResource());
                    }
                    catch (RepositoryException e) {
                        log.error("could not get resource from hit", (Throwable)e);
                    }
                }
            } else {
                log.warn("cannot execute query: no session found in request");
            }
        } else if (paths != null && paths.length >= 1) {
            log.debug("multiple resources");
            resources.add(request.getResource());
            String resPath = request.getResource().getPath();
            for (String path : paths) {
                Resource res;
                if (resPath.equals(path) || (res = resolver.resolve(path)) == null) continue;
                resources.add(res);
            }
        } else {
            log.debug("single resource only");
            resources.add(request.getResource());
        }
        if (log.isDebugEnabled()) {
            for (Resource res : resources) {
                log.debug("resource: " + (Object)res);
            }
        }
        return resources;
    }

    protected void bindQueryBuilder(QueryBuilder queryBuilder) {
        this.queryBuilder = queryBuilder;
    }

    protected void unbindQueryBuilder(QueryBuilder queryBuilder) {
        if (this.queryBuilder == queryBuilder) {
            this.queryBuilder = null;
        }
    }

    private static class SearchPathComparator
    implements Comparator<String> {
        private List<String> searchPath;

        public SearchPathComparator(List<String> searchPath) {
            this.searchPath = searchPath;
        }

        @Override
        public int compare(String path1, String path2) {
            int index1 = this.getSearchPathIndex(path1);
            int index2 = this.getSearchPathIndex(path2);
            return index2 - index1;
        }

        private int getSearchPathIndex(String path) {
            for (int i = 0; i < this.searchPath.size(); ++i) {
                if (!path.startsWith(this.searchPath.get(i))) continue;
                return i;
            }
            return this.searchPath.size() + 1;
        }
    }

}