ren.hankai.cordwood.web.breadcrumb.BreadCrumbInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for ren.hankai.cordwood.web.breadcrumb.BreadCrumbInterceptor.java

Source

/*******************************************************************************
 * Copyright (C) 2018 hankai
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ******************************************************************************/

package ren.hankai.cordwood.web.breadcrumb;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * <p>???????????
 * <b>NavigationItem</b> ????<b>?</b>
 *  {@link BreadCrumbInterceptor#BREAD_CRUMB_LINKS BREAD_CRUMB_LINKS} ??
 * {@link BreadCrumbInterceptor#CURRENT_BREAD_CRUMB CURRENT_BREAD_CRUMB} ????</p>
 * <p>??{} </p>
 *
 * <pre>
 *  ""
 * "" &lt;=&gt; LinkedHashMap {
 *     "" &lt;=&gt; BreadCrumbLink("", "",     true, null)
 * }
 *
 *  ??
 * "(family)" &lt;=&gt; LinkedHashMap {
 *    "?" &lt;=&gt; BreadCrumbLink("", "?", true, ""),
 *    "" &lt;=&gt; BreadCrumbLink("", "",     false, null)
 * }
 *
 *  ?
 * "(family)" &lt;=&gt; LinkedHashMap {
 *    "(label)" &lt;=&gt; BreadCrumbLink("", "", true, "?"),
 *    "?(label)" &lt;=&gt; BreadCrumbLink("", "?", false, ""),
 *    "(label)" &lt;=&gt; BreadCrumbLink("", "",  false, null)
 * }
 *
 * ????? \ ? \ <b></b>
 *
 *  ??
 * "(family)" &lt;=&gt; LinkedHashMap {
 *    "?" &lt;=&gt; BreadCrumbLink("", "?", true, ""),
 *    "" &lt;=&gt; BreadCrumbLink("", "", false, null)
 * }
 * </pre>
 *
 * @author hankai
 * @version 1.0.0
 * @since Dec 6, 2016 2:56:50 PM
 * @see ren.hankai.cordwood.web.breadcrumb.NavigationItem
 * @see ren.hankai.cordwood.web.breadcrumb.BreadCrumbLink
 */
public class BreadCrumbInterceptor implements HandlerInterceptor {

    /**
     * ?? <code>Map&lt;String, LinkedHashMap&lt;String, BreadCrumbLink&gt;&gt;</code>
     */
    public static final String BREAD_CRUMB_LINKS = "breadCrumb";
    /**
     * ?? <code>LinkedList&lt;BreadCrumbLink&gt;</code>
     */
    public static final String CURRENT_BREAD_CRUMB = "currentBreadCrumb";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        final Annotation[] declaredAnnotations = getDeclaredAnnotationsForHandler(handler);
        if ((declaredAnnotations != null) && (declaredAnnotations.length > 0)) {
            final HttpSession session = request.getSession();
            emptyCurrentBreadCrumb(session);
            for (final Annotation annotation : declaredAnnotations) {
                if (annotation.annotationType().equals(NavigationItem.class)) {
                    processAnnotation(request, session, annotation);
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) throws Exception {
    }

    private void emptyCurrentBreadCrumb(HttpSession session) {
        session.setAttribute(CURRENT_BREAD_CRUMB, new LinkedList<BreadCrumbLink>());
    }

    /**
     * ?HTTPHandler??
     *
     * @param request HTTP
     * @param session HTTP?
     * @param annotation handler
     * @author hankai
     * @since Nov 22, 2018 3:54:10 PM
     */
    private void processAnnotation(HttpServletRequest request, HttpSession session, Annotation annotation) {
        final NavigationItem link = (NavigationItem) annotation;
        final String family = link.family();

        Map<String, LinkedHashMap<String, BreadCrumbLink>> breadCrumb = getBreadCrumbLinksFromSession(session);

        if (breadCrumb == null) {
            breadCrumb = new HashMap<>();
        }

        LinkedHashMap<String, BreadCrumbLink> familyMap = breadCrumb.get(family);

        if (familyMap == null) {
            familyMap = new LinkedHashMap<>();
            breadCrumb.put(family, familyMap);
        }

        final BreadCrumbLink breadCrumbLink = getBreadCrumbLink(request, link, familyMap);
        final LinkedList<BreadCrumbLink> currentBreadCrumb = new LinkedList<>();
        generateBreadCrumbsRecursively(breadCrumbLink, currentBreadCrumb);
        session.setAttribute(CURRENT_BREAD_CRUMB, currentBreadCrumb);
        session.setAttribute(BREAD_CRUMB_LINKS, breadCrumb);
    }

    /**
     * ????
     *
     * @param request HTTP
     * @param link ?
     * @param familyMap 
     * @return ??
     * @author hankai
     * @since Nov 22, 2018 3:55:39 PM
     */
    private BreadCrumbLink getBreadCrumbLink(HttpServletRequest request, NavigationItem link,
            LinkedHashMap<String, BreadCrumbLink> familyMap) {
        BreadCrumbLink breadCrumbLink;
        final BreadCrumbLink breadCrumbObject = familyMap.get(link.label());
        resetBreadCrumbs(familyMap);
        if (breadCrumbObject != null) {
            breadCrumbObject.setCurrentPage(true);
            breadCrumbLink = breadCrumbObject;
        } else {
            breadCrumbLink = new BreadCrumbLink(link.family(), link.label(), true, link.parent());
            final StringBuffer relativeUrl = new StringBuffer(request.getRequestURI());
            if (StringUtils.isNotEmpty(request.getQueryString())) {
                relativeUrl.append("?" + request.getQueryString());
            }
            breadCrumbLink.setUrl(relativeUrl.toString());
            familyMap.put(link.label(), breadCrumbLink);
        }
        createRelationships(familyMap, breadCrumbLink);
        return breadCrumbLink;
    }

    /**
     * HTTP???
     *
     * @param session HTTP?
     * @return ???
     * @author hankai
     * @since Nov 22, 2018 3:57:00 PM
     */
    @SuppressWarnings("unchecked")
    private Map<String, LinkedHashMap<String, BreadCrumbLink>> getBreadCrumbLinksFromSession(HttpSession session) {
        final Map<String, LinkedHashMap<String, BreadCrumbLink>> breadCrumb = (Map<String, LinkedHashMap<String, BreadCrumbLink>>) session
                .getAttribute(BREAD_CRUMB_LINKS);
        return breadCrumb;
    }

    /**
     * ?HTTPHandler
     *
     * @param handler HTTPHandler
     * @return 
     * @author hankai
     * @since Nov 22, 2018 3:58:22 PM
     */
    private Annotation[] getDeclaredAnnotationsForHandler(Object handler) {
        if (handler instanceof HandlerMethod) {
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            final Method method = handlerMethod.getMethod();
            final Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
            return declaredAnnotations;
        } else {
            return null;
        }
    }

    /**
     * ??
     *
     * @param familyMap ?
     * @author hankai
     * @since Nov 22, 2018 3:47:13 PM
     */
    private void resetBreadCrumbs(LinkedHashMap<String, BreadCrumbLink> familyMap) {
        for (final BreadCrumbLink breadCrumbLink : familyMap.values()) {
            breadCrumbLink.setCurrentPage(false);
        }
    }

    /**
     * ??
     *
     * @param link 
     * @param breadCrumbLinks ?
     * @author hankai
     * @since Nov 22, 2018 3:48:35 PM
     */
    private void generateBreadCrumbsRecursively(BreadCrumbLink link, LinkedList<BreadCrumbLink> breadCrumbLinks) {
        if (link.getPrevious() != null) {
            generateBreadCrumbsRecursively(link.getPrevious(), breadCrumbLinks);
        }
        breadCrumbLinks.add(link);
    }

    /**
     * 
     *
     * @param familyMap 
     * @param newLink 
     * @author hankai
     * @since Nov 22, 2018 3:50:12 PM
     */
    private void createRelationships(LinkedHashMap<String, BreadCrumbLink> familyMap, BreadCrumbLink newLink) {
        final Collection<BreadCrumbLink> values = familyMap.values();
        for (final BreadCrumbLink breadCrumbLink : values) {
            if (breadCrumbLink.getLabel().equalsIgnoreCase(newLink.getParentKey())) {
                breadCrumbLink.addNext(newLink);
                newLink.setPrevious(breadCrumbLink);
                newLink.setParent(breadCrumbLink);
            }
        }
    }
}