001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $
018 */
019
020package org.nuxeo.ecm.platform.ui.web.shield;
021
022import java.io.Serializable;
023import java.util.Map;
024
025import javax.faces.context.ExternalContext;
026import javax.faces.context.FacesContext;
027import javax.faces.event.PhaseId;
028import javax.interceptor.AroundInvoke;
029import javax.interceptor.InvocationContext;
030import javax.servlet.ServletRequest;
031import javax.servlet.http.HttpServletRequest;
032import javax.transaction.SystemException;
033
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.jboss.seam.contexts.Context;
037import org.jboss.seam.contexts.Contexts;
038import org.jboss.seam.contexts.FacesLifecycle;
039import org.jboss.seam.faces.Redirect;
040import org.jboss.seam.transaction.Transaction;
041import org.nuxeo.common.utils.ExceptionUtils;
042import org.nuxeo.ecm.core.api.DocumentSecurityException;
043import org.nuxeo.ecm.core.api.NuxeoException;
044import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants;
045import org.nuxeo.ecm.platform.web.common.exceptionhandling.ExceptionHelper;
046
047/**
048 * Error handling interceptor.
049 * <p>
050 * Redirects to the good error page if an exception is caught: login page on security exception, themed error page on
051 * other exceptions and unthemed error page when another error is caught while rendering the error page.
052 *
053 * @author <a href="mailto:rcaraghin@nuxeo.com">Razvan Caraghin</a>
054 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
055 * @deprecated No need anymore, error is processed in NuxeoExceptionFilter
056 */
057@Deprecated
058public class NuxeoErrorInterceptor implements Serializable {
059
060    private static final long serialVersionUID = 6519836435278721L;
061
062    private static final Log log = LogFactory.getLog(NuxeoErrorInterceptor.class);
063
064    private static final String GENERIC_ERROR_VIEW_ID = "/generic_error_page.xhtml";
065
066    private static final String UNTHEMED_ERROR_VIEW_ID = "/unthemed_generic_error_page.xhtml";
067
068    private static final String LOGIN_VIEW_ID = "/login.jsp";
069
070    @AroundInvoke
071    public Object invokeAndWrapExceptions(InvocationContext invocation) throws SystemException,
072            DocumentSecurityException {
073        try {
074            // log.debug("Before invocation...");
075            return invocation.proceed();
076        } catch (Exception t) { // deals with interrupt below
077            ExceptionUtils.checkInterrupt(t);
078
079            if (Transaction.instance().isActive()) {
080                Transaction.instance().setRollbackOnly();
081            }
082
083            FacesContext facesContext = FacesContext.getCurrentInstance();
084
085            if (FacesLifecycle.getPhaseId() == PhaseId.RENDER_RESPONSE) {
086                if (ExceptionHelper.isSecurityError(t)) {
087                    if (facesContext != null) {
088                        Object req = facesContext.getExternalContext().getRequest();
089                        if (req instanceof ServletRequest) {
090                            ServletRequest request = (ServletRequest) req;
091                            request.setAttribute("securityException", t);
092                        }
093                    }
094                    throw new DocumentSecurityException("Security Error during call of "
095                            + invocation.getTarget().toString(), t);
096                }
097            }
098
099            NuxeoException cException = new NuxeoException(t);
100            // redirect is not allowed during render response phase => throw
101            // the error without redirecting
102            if (FacesLifecycle.getPhaseId() == PhaseId.RENDER_RESPONSE) {
103                if (facesContext != null) {
104                    Object req = facesContext.getExternalContext().getRequest();
105                    if (req instanceof ServletRequest) {
106                        ServletRequest request = (ServletRequest) req;
107                        request.setAttribute("applicationException", cException);
108                    }
109                }
110                throw cException;
111            }
112
113            // check if previous page was already an error page to avoid
114            // redirect cycle
115            if (facesContext != null) {
116                ExternalContext externalContext = facesContext.getExternalContext();
117                if (externalContext != null) {
118                    Map<String, String[]> requestMap = externalContext.getRequestHeaderValuesMap();
119                    if (requestMap != null) {
120                        String[] previousPage = requestMap.get("Referer");
121                        if (previousPage != null && previousPage.length != 0) {
122                            String pageName = previousPage[0];
123                            if (pageName != null && pageName.contains("error_page")) {
124                                redirectToErrorPage(UNTHEMED_ERROR_VIEW_ID);
125                                return null;
126                            }
127                        }
128                    }
129                }
130            }
131
132            String redirectToViewId = null;
133            try {
134                log.error("Exception caught, redirecting to the error page...", cException);
135                final Context sessionContext = Contexts.getSessionContext();
136                // set applicationException in session hoping
137                // ErrorPageActionListener will inject it
138                sessionContext.set("applicationException", cException);
139                if (ExceptionHelper.isSecurityError(t) || cException.getCause() instanceof DocumentSecurityException) {
140                    redirectToViewId = LOGIN_VIEW_ID;
141                } else {
142                    redirectToViewId = GENERIC_ERROR_VIEW_ID;
143                }
144            } catch (RuntimeException e) {
145                // might be the case when session context is null
146                log.error(e, e);
147                redirectToViewId = UNTHEMED_ERROR_VIEW_ID;
148            }
149
150            if (redirectToErrorPage(redirectToViewId)) {
151                return null;
152            } else {
153                log.info("Unable to handle exception in web-context. " + "It might be an external (soap) request. "
154                        + "Throwing further...");
155                log.error("Original error", t);
156                throw cException;
157            }
158        }
159    }
160
161    private boolean redirectToErrorPage(String viewId) {
162        final String logPrefix = "<redirectToErrorPage> ";
163
164        final FacesContext facesContext = FacesContext.getCurrentInstance();
165        // we cannot call redirect if facesContext is null (Seam internals)
166        if (facesContext == null) {
167            // TODO decrease debug level
168            log.info(logPrefix + "cannot redirect to error page");
169            return false;
170        }
171
172        HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
173        // avoid further redirection
174        request.setAttribute(NXAuthConstants.DISABLE_REDIRECT_REQUEST_KEY, Boolean.TRUE);
175
176        Redirect.instance().setViewId(viewId);
177        Redirect.instance().execute();
178        return true;
179    }
180
181}