package org.fenixedu.bennu.portal.servlet; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.fenixedu.bennu.portal.domain.MenuContainer; import org.fenixedu.bennu.portal.domain.MenuFunctionality; import org.fenixedu.bennu.portal.domain.PortalConfiguration; /** * Filter that translates semantic URLs to {@link MenuFunctionality}s. Requests whose path matches that of a functionality are * handled by the functionality's {@link SemanticURLHandler}, whereas any other request will simply continue the chain. In this * scenario, the underlying presentation technology should attempt to resolve the {@link MenuFunctionality}. * * <p> * Implementation note: This filter is programmatically registered, to ensure that it is the last filter in the chain to be * executed. This ensures that any filter declared in other modules are given a chance to run. * </p> * * @author João Carvalho (joao.pedro.carvalho@tecnico.ulisboa.pt) * */ public class BennuPortalDispatcher implements Filter { private int contextPathLength = -1; @Override public void init(FilterConfig filterConfig) throws ServletException { contextPathLength = filterConfig.getServletContext().getContextPath().length(); } @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String path = trim(request.getRequestURI()); MenuFunctionality functionality = selectFunctionality(path); if (functionality != null) { selectFunctionality(request, functionality); PortalBackendRegistry.getPortalBackend(functionality.getProvider()).getSemanticURLHandler() .handleRequest(functionality, request, response, chain); } else { chain.doFilter(request, response); } } private MenuFunctionality selectFunctionality(String path) { String[] parts = path.split("/"); MenuContainer root = PortalConfiguration.getInstance().getMenu(); return root.findFunctionalityWithPath(parts); } /** * Returns the selected {@link MenuFunctionality} from the given request, or null if no functionality is selected. * * @param request * The request for which to retrieve the functionality * @return * The functionality associated with the given request. {@code null} if no functionality is mapped. * @throws NullPointerException * If {@code request} is {@code null} */ public static MenuFunctionality getSelectedFunctionality(HttpServletRequest request) { return (MenuFunctionality) request.getAttribute("PORTAL_SELECTED_FUNCTIONALITY"); } /** * Selects the given {@link MenuFunctionality} for the given request. * * @param request * The request for which to select the given functionality * @param functionality * The functionality to select * @throws NullPointerException * If {@code request} is {@code null} */ public static void selectFunctionality(HttpServletRequest request, MenuFunctionality functionality) { request.setAttribute("PORTAL_SELECTED_FUNCTIONALITY", functionality); } /** * Trims the given string, removing all trailing and leading slashes. It also removes the context path. */ private String trim(String value) { int len = value.length(); int st = contextPathLength; char[] val = value.toCharArray(); while ((st < len) && (val[st] == '/')) { st++; } while ((st < len) && (val[len - 1] == '/')) { len--; } return ((st > 0) || (len < value.length())) ? value.substring(st, len) : value; } }