jp.co.opentone.bsol.linkbinder.view.exception.LinkBinderExceptionHandler.java Source code

Java tutorial

Introduction

Here is the source code for jp.co.opentone.bsol.linkbinder.view.exception.LinkBinderExceptionHandler.java

Source

/*
 * Copyright 2016 OPEN TONE Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jp.co.opentone.bsol.linkbinder.view.exception;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;

import com.sun.faces.renderkit.ServerSideStateHelper;
import com.sun.faces.util.TypedCollections;

import jp.co.opentone.bsol.framework.core.config.SystemConfig;
import jp.co.opentone.bsol.framework.core.exception.InvalidOperationRuntimeException;
import jp.co.opentone.bsol.framework.core.message.Message;
import jp.co.opentone.bsol.framework.core.message.MessageHolder;
import jp.co.opentone.bsol.framework.core.message.Messages;
import jp.co.opentone.bsol.framework.core.util.LogUtil;
import jp.co.opentone.bsol.framework.web.view.Page;
import jp.co.opentone.bsol.framework.web.view.flash.Flash;
import jp.co.opentone.bsol.framework.web.view.util.ViewHelper;
import jp.co.opentone.bsol.linkbinder.Constants;
import jp.co.opentone.bsol.linkbinder.dto.User;

/**
 * @author opentone
 */
public class LinkBinderExceptionHandler extends ExceptionHandlerWrapper {

    /** logger. */
    private static Logger log = LogUtil.getLogger();

    /** ?? {@link ExceptionHandler}. */
    private ExceptionHandler wrapped;

    /**
     * .
     */
    private String errorPage = "/error.jsf";

    /**
     * ?? {@link ExceptionHandler} ???.
     * @param wrapped ??
     */
    public LinkBinderExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    /* (non-Javadoc)
     * @see javax.faces.context.ExceptionHandlerWrapper#getWrapped()
     */
    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

    /* (non-Javadoc)
     * @see javax.faces.context.ExceptionHandlerWrapper#handle()
     */
    @Override
    public void handle() throws FacesException {
        Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator();
        while (it.hasNext()) {
            ExceptionQueuedEvent event = it.next();
            ExceptionQueuedEventContext c = (ExceptionQueuedEventContext) event.getSource();
            Throwable t = c.getException();

            HttpServletRequest req = (HttpServletRequest) c.getContext().getExternalContext().getRequest();
            HttpServletResponse res = (HttpServletResponse) c.getContext().getExternalContext().getResponse();
            handleException(req, res, t);
        }
    }

    public void handleException(HttpServletRequest req, HttpServletResponse res, Throwable e) {
        if (e.getCause() != null && e.getCause() instanceof InvalidOperationRuntimeException) {
            log.warn("invalid operation occurred. request was failed.");
        }

        // ViewExpiredException??
        if (isViewExpiredException(e)) {
            if (isLogViewExpiredException()) {
                logRequest(req);
                logViewMap();
            } else {
                log.warn("no logging for ViewExpiredException");
            }
        }

        setMessage(e);
        req.getSession().setAttribute("jp.co.opentone.bsol.exception", e);
        try {
            res.sendRedirect(req.getContextPath() + errorPage);
        } catch (IOException ex) {
            log.error("redirect failed.", ex);
        }

    }

    private void logRequest(HttpServletRequest req) {
        log.error("Requested: {} {}", req.getMethod(), req.getRequestURI());
        Enumeration<?> enm = req.getHeaderNames();
        log.error("Header:");
        while (enm.hasMoreElements()) {
            String name = (String) enm.nextElement();
            log.error("   {} = {}", name, req.getHeader(name));
        }

        log.error(" Parameters:");
        @SuppressWarnings("unchecked")
        Map<String, String[]> parameterMap = req.getParameterMap();
        for (Map.Entry<String, String[]> e : parameterMap.entrySet()) {
            log.error("  {} = {}", e.getKey(), StringUtils.join(e.getValue()));
        }
    }

    @SuppressWarnings("unchecked")
    private void logViewMap() {
        log.error(" ViewMap entries:");
        try {
            FacesContext c = FacesContext.getCurrentInstance();
            if (c == null) {
                log.warn(" FacesContext was released.");
                return;
            }
            ExternalContext externalContext = c.getExternalContext();
            if (externalContext == null) {
                log.warn(" ExternalContext was released.");
                return;
            }

            Map<String, Object> sessionMap = externalContext.getSessionMap();
            if (sessionMap == null) {
                log.warn(" SessionMap does not exist.");
                return;
            }

            Object u = sessionMap.get("currentUser");
            if (u != null && u instanceof User) {
                log.error("  currentUser = {}", ((User) u).getUserId());
            }
            @SuppressWarnings("rawtypes")
            Map<String, Map> logicalMap = TypedCollections.dynamicallyCastMap(
                    (Map) sessionMap.get(ServerSideStateHelper.LOGICAL_VIEW_MAP), String.class, Map.class);
            if (logicalMap == null)
                return;

            log.error("  size: {}", logicalMap.size());
            for (@SuppressWarnings("rawtypes")
            Map.Entry<String, Map> e : logicalMap.entrySet()) {
                log.error("  {} = [", e.getKey());
                for (Map.Entry<String, Object[]> ae : ((Map<String, Object[]>) e.getValue()).entrySet()) {
                    Object[] val = ae.getValue();
                    StringBuilder sb = new StringBuilder();
                    sb.append("    ").append(ae.getKey()).append(" = ");
                    if (val.length == 2) {
                        sb.append("      [ structure = ").append(val[0]);
                        sb.append(", savedState = ").append(logViewMapEntry(val[1])).append("]");
                    } else {
                        for (Object v : val) {
                            sb.append("      ").append(v).append(',');
                        }
                    }
                    log.error(sb.toString());
                }
                log.error("    ]");
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private String logViewMapEntry(Object val) {
        if (val == null)
            return null;
        if (!(val instanceof Map<?, ?>))
            return null;

        List<String> result = new ArrayList<String>();
        Map<String, Object> m = (Map<String, Object>) val;
        for (Map.Entry<String, Object> e : m.entrySet()) {
            StringBuilder str = new StringBuilder();
            str.append(e.getKey()).append(" = ");
            Object value = e.getValue();
            if (value != null) {
                str.append("class :").append(value.getClass().getSimpleName()).append(' ');
            }
            str.append(value);

            result.add(str.toString());
        }

        return StringUtils.join(result, ",");
    }

    private boolean isLogViewExpiredException() {
        String filename = SystemConfig.getValue(Constants.KEY_LOG_SWITCH_VIEWEXPIREDEXCEPTION);
        if (StringUtils.isEmpty(filename))
            return false;

        File f = new File(filename);
        return f.exists();
    }

    private boolean isViewExpiredException(Throwable t) {
        return t instanceof ViewExpiredException
                || (t.getCause() != null && t.getCause() instanceof ViewExpiredException);
    }

    /**
     * ?????????.
     * @param e ??
     */
    void setMessage(Throwable e) {
        //  FacesContext?????
        //  ?????
        if (FacesContext.getCurrentInstance() == null) {
            log.warn("FacesContext was released. Nothing to do.");
            return;
        }

        ViewHelper helper = new ViewHelper();
        Message message = getMessage(e);
        FacesMessage m;
        if (message != null) {
            m = helper.createFacesMessage(message);
        } else {
            m = createFatalMessage(e);
        }
        //  ????????
        setToken(m);
        log.error(m.getDetail(), e);

        Flash flash = new Flash();
        flash.setValue(Page.KEY_FLASH_MASSAGE, m);
    }

    void setToken(FacesMessage m) {
        long token = System.currentTimeMillis();
        String org = m.getDetail();
        m.setDetail(String.format("%s (%s)", org, token));
    }

    FacesMessage createFatalMessage(Throwable e) {
        if (e.getCause() == null) {
            FacesMessage m = new FacesMessage();
            m.setSeverity(FacesMessage.SEVERITY_FATAL);
            m.setSummary(m.getSeverity().toString());
            m.setDetail(String.format("Unhandled exception : %s", e.getClass().getSimpleName()));
            return m;
        } else {
            return createFatalMessage(e.getCause());
        }
    }

    /**
     * ????????.
     * @param e ??
     * @return . ???????null
     */
    Message getMessage(Throwable e) {
        if (e instanceof MessageHolder) {
            String messageCode = ((MessageHolder) e).getMessageCode();
            Object[] vars = ((MessageHolder) e).getMessageVars();
            return Messages.getMessage(messageCode, vars);
        }
        if (e instanceof InvalidOperationRuntimeException) {
            // ????????
            // ???????????
            return ((InvalidOperationRuntimeException) e).getCreatedMessage();
        }
        if (e.getCause() == null) {
            return null;
        }
        return getMessage(e.getCause());
    }
}