jease.cms.web.servlet.JeaseController.java Source code

Java tutorial

Introduction

Here is the source code for jease.cms.web.servlet.JeaseController.java

Source

/*
Copyright (C) 2016 maik.jablonski@jease.org
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jease.cms.web.servlet;

import java.io.IOException;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;

import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jease.Names;
import jease.Registry;
import jease.cmf.domain.Node;
import jease.cmf.service.Nodes;
import jease.cms.domain.Redirect;
import jfix.db4o.Database;
import jfix.servlet.ResponseRewriter;
import jfix.servlet.Servlets;

import org.apache.commons.lang3.StringUtils;

@WebFilter(urlPatterns = { "/*" }, dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD,
        DispatcherType.INCLUDE, DispatcherType.ERROR })
public class JeaseController implements javax.servlet.Filter {

    private static Supplier<List<Redirect>> redirectSupplier = () -> {
        List<Redirect> redirects = Database.query(Redirect.class);
        redirects.sort(Comparator.comparing(Redirect::getTimestamp));
        return redirects;
    };

    private static Supplier<Function<String, String>> rewriterSupplier = () -> {
        try {
            String jeaseSiteRewriter = Registry.getParameter(Names.JEASE_SITE_REWRITER);
            return (Function<String, String>) Class.forName(jeaseSiteRewriter).newInstance();
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
            return null;
        }
    };

    private static String contextPath;
    private static String dispatcher;
    private static Pattern servlets;
    private static Set<String> locales;

    public static String getContextPath() {
        return contextPath;
    }

    public void init(FilterConfig config) throws ServletException {
        contextPath = config.getServletContext().getContextPath();
        dispatcher = config.getServletContext().getInitParameter(Names.JEASE_SITE_DISPATCHER);
        servlets = Pattern.compile(
                String.format("/(%s).*", config.getServletContext().getInitParameter(Names.JEASE_SITE_SERVLETS)));
        locales = new HashSet<>();
        for (Locale locale : Locale.getAvailableLocales()) {
            locales.add(locale.getLanguage());
        }
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        String uri = request.getRequestURI();

        // Strip jsessionid from URI.
        int jsessionidIndex = uri.indexOf(";jsessionid=");
        if (jsessionidIndex != -1) {
            uri = uri.substring(0, jsessionidIndex);
        }

        // Process internal context prefix
        int tilde = uri.indexOf("~");
        if (tilde != -1) {
            String path = uri.substring(tilde + 1);
            response.sendRedirect(response
                    .encodeRedirectURL(buildURI(request.getContextPath() + path, request.getQueryString())));
            return;
        }

        // Try to resolve node from URI (without context path).
        String nodePath = uri.substring(request.getContextPath().length());
        Node node = Nodes.getByPath(nodePath);

        // Process redirect rules
        if (node == null && !servlets.matcher(nodePath).matches()) {
            String sourceURI = buildURI(nodePath, request.getQueryString());
            String targetURI = rewriteURI(sourceURI);
            if (!targetURI.equals(sourceURI)) {
                if (targetURI.contains("://")) {
                    response.sendRedirect(response.encodeRedirectURL(targetURI));
                } else {
                    response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + targetURI));
                }
                return;
            }
        }

        // Save "virtual" root node. Per default it is the absolute root of the
        // instance.
        // If a node with the server name exists, this node is used as virtual
        // root.
        if (request.getAttribute("Root") == null) {
            String server = Servlets.getServerName(request).replaceFirst("www.", "");
            Node root = Nodes.getRoot() != null ? Nodes.getRoot().getChild(server) : null;
            if (root == null) {
                root = Nodes.getRoot();
            }
            if (node != null) {
                if (node.getParent() == root && locales.contains(node.getId())) {
                    root = node;
                } else {
                    for (Node parent : node.getParents()) {
                        if (parent.getParent() == root && locales.contains(parent.getId())) {
                            root = parent;
                            break;
                        }
                    }
                }
            }
            request.setAttribute("Root", root);
            if (node != null && root.getParent() == node) {
                response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + root.getPath()));
                return;
            }
        }

        // If no node is found, process filter chain.
        if (node == null) {
            chain.doFilter(request, response);
            return;
        }

        // Redirect if trailing slash is missing for containers.
        if (node.isContainer() && !uri.endsWith("/")) {
            response.sendRedirect(response.encodeRedirectURL(buildURI(uri + "/", request.getQueryString())));
        } else {
            // Set node into request scope and forward to dispatcher
            request.setAttribute(Node.class.getSimpleName(), node);
            request.setAttribute(Names.JEASE_SITE_DISPATCHER, dispatcher);
            Function<String, String> rewriter = StringUtils.isNotBlank(
                    Registry.getParameter(Names.JEASE_SITE_REWRITER)) ? Database.query(rewriterSupplier) : null;
            request.getRequestDispatcher(dispatcher).forward(request,
                    rewriter != null ? new ResponseRewriter(response, rewriter) : response);
        }
    }

    private String buildURI(String uri, String query) {
        if (query != null) {
            return String.format("%s%s%s", uri, uri.contains("?") ? "&" : "?", query);
        } else {
            return uri;
        }
    }

    private String rewriteURI(String uri) {
        for (Redirect redirect : Database.query(redirectSupplier)) {
            String output = redirect.transform(uri);
            if (!output.equals(uri)) {
                return output;
            }
        }
        return uri;
    }

}