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

com.composum.sling.core.servlet.ServletOperationSet Maven / Gradle / Ivy

There is a newer version: 4.3.4
Show newest version
package com.composum.sling.core.servlet;

import com.composum.sling.core.ResourceHandle;
import com.composum.sling.core.mapping.MappingRules;
import com.composum.sling.core.util.RequestUtil;
import com.composum.sling.core.util.SlingResourceUtil;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestPathInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * A set of operation for the implementation of one servlet based on different operations.
 * This set manages the operation for the servlet and is a delegate for the servlet interface methods.
 */
public class ServletOperationSet, O extends Enum> {

    private static final Logger LOG = LoggerFactory.getLogger(ServletOperationSet.class);

    public enum Method {GET, POST, PUT, DELETE}

    /** the default operation keys for each provided extension */
    protected Map> operationDefaults = new HashMap<>();

    /** the operations map set up during servlet initialization */
    protected Map>> operationMap = new HashMap<>();

    protected final E defaultExtension;

    public ServletOperationSet(E defaultExtension) {
        this.defaultExtension = defaultExtension;
    }

    /**
     * Retrieves the servlet operation requested for the used HTTP method.
     * Looks in the selectors for a operation and gives their implementation in the extensions context.
     *
     * @param request the servlet request
     * @param method  the requested HTTP method
     * @return the operation or 'null', if the requested combination of selector
     * and extension has no implementation for the given HTTP method
     */
    public ServletOperation getOperation(SlingHttpServletRequest request, Method method) {
        ServletOperation operation = null;
        E extension = RequestUtil.getExtension(request, defaultExtension);
        Map extensionDefaults = operationDefaults.get(method);
        if (extensionDefaults != null) {
            O defaultOperation = extensionDefaults.get(extension);
            if (defaultOperation != null) {
                Map> extensions = operationMap.get(method);
                if (extensions != null) {
                    Map operations = extensions.get(extension);
                    if (operations != null) {
                        operation = operations.get(RequestUtil.getSelector(request, defaultOperation));
                    }
                }
            }
        }
        return operation;
    }

    public void setOperation(Method method, E extension, O operation, ServletOperation implementation) {
        setOperation(method, extension, operation, implementation, false);
    }

    public void setOperation(Method method, E extension, O operation,
                             ServletOperation implementation, boolean isDefault) {
        Map> extensions = operationMap.computeIfAbsent(method, k -> new HashMap<>());
        Map operations = extensions.computeIfAbsent(extension, k -> new HashMap<>());
        if (implementation != null) {
            operations.put(operation, implementation);
        } else {
            operations.remove(operation);
        }
        // set as default operation if determined as default or if no default operation
        // determined before (the first registered operation is implicit the default)
        if (isDefault || getDefaultOperation(method, extension) == null) {
            setDefaultOperation(method, extension, operation);
        }
    }

    public O getDefaultOperation(Method method, E extension) {
        O operation = null;
        Map extensions = operationDefaults.get(method);
        if (extensions != null) {
            operation = extensions.get(extension);
        }
        return operation;
    }

    public void setDefaultOperation(Method method, E extension, O operation) {
        Map extensions = operationDefaults.computeIfAbsent(method, k -> new HashMap<>());
        if (operation != null) {
            extensions.put(extension, operation);
        } else {
            extensions.remove(extension);
        }
    }

    //
    // the Servlet interface delegates
    //

    /**
     * the extension hook if the resource is not simply build by the suffix
     */
    protected ResourceHandle getResource(SlingHttpServletRequest request) {
        return AbstractServiceServlet.getResource(request);
    }

    // GET access

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        ServletOperation operation = getOperation(request, Method.GET);

        if (operation != null) {
            try {

                ResourceHandle resource = getResource(request);
                LOG.debug("Calling GET {} for {} with {}", operation.getClass().getSimpleName(),
                        SlingResourceUtil.getPath(resource));
                operation.doIt(request, response, resource);

            } catch (RepositoryException ex) {
                LOG.error(ex.getMessage(), ex);
                if (response.isCommitted()) {
                    OutputStream log = response.getOutputStream();
                    log.write(ex.toString().getBytes(MappingRules.CHARSET));
                } else {
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.toString());
                }
            }

        } else {
            sendInvalidOperation(request, response, Method.GET);
        }
    }

    // POST method

    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        ServletOperation operation = getOperation(request, Method.POST);

        if (operation != null) {
            try {

                ResourceHandle resource = getResource(request);
                LOG.debug("Calling POST {} with {}", operation.getClass().getSimpleName(),
                        SlingResourceUtil.getPath(resource));
                operation.doIt(request, response, resource);

            } catch (RepositoryException ex) {
                LOG.error(ex.getMessage(), ex);
                if (response.isCommitted()) {
                    OutputStream log = response.getOutputStream();
                    log.write(ex.toString().getBytes(MappingRules.CHARSET));
                } else {
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.toString());
                }
            }

        } else {
            sendInvalidOperation(request, response, Method.POST);
        }
    }

    // PUT upload

    protected void doPut(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        ServletOperation operation = getOperation(request, Method.PUT);

        if (operation != null) {
            try {

                ResourceHandle resource = getResource(request);
                LOG.debug("Calling PUT {} with {}", operation.getClass().getSimpleName(),
                        SlingResourceUtil.getPath(resource));
                operation.doIt(request, response, resource);

            } catch (RepositoryException ex) {
                LOG.error(ex.getMessage(), ex);
                if (response.isCommitted()) {
                    OutputStream log = response.getOutputStream();
                    log.write(ex.toString().getBytes(MappingRules.CHARSET));
                } else {
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.toString());
                }
            }

        } else {
            sendInvalidOperation(request, response, Method.PUT);
        }
    }

    // DELETE removal

    protected void doDelete(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {

        ServletOperation operation = getOperation(request, Method.DELETE);

        if (operation != null) {
            try {

                ResourceHandle resource = getResource(request);
                LOG.debug("Calling DELETE {} with {}", operation.getClass().getSimpleName(),
                        SlingResourceUtil.getPath(resource));
                operation.doIt(request, response, resource);

            } catch (RepositoryException ex) {
                LOG.error(ex.getMessage(), ex);
                if (response.isCommitted()) {
                    OutputStream log = response.getOutputStream();
                    log.write(ex.toString().getBytes(MappingRules.CHARSET));
                } else {
                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.toString());
                }
            }

        } else {
            sendInvalidOperation(request, response, Method.DELETE);
        }
    }

    //
    // helpers
    //

    public void sendInvalidOperation(SlingHttpServletRequest request,
                                     SlingHttpServletResponse response,
                                     Method method) throws IOException {
        RequestPathInfo pathInfo = request.getRequestPathInfo();
        String message = "invalid operation '" + method.name() + ":"
                + pathInfo.getSelectorString() + "." + pathInfo.getExtension() + "'";
        try {
            throw new Exception(message);
        } catch (Exception ex) {
            LOG.error(message, ex);
        }
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy