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