001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ui.error;
029
030import org.opencms.file.CmsObject;
031import org.opencms.flex.CmsFlexController;
032import org.opencms.jsp.util.Messages;
033import org.opencms.main.CmsLog;
034import org.opencms.main.CmsMultiException;
035import org.opencms.main.I_CmsThrowable;
036import org.opencms.main.OpenCms;
037import org.opencms.ui.A_CmsUI;
038import org.opencms.ui.CmsVaadinUtils;
039import org.opencms.ui.apps.CmsLegacyApp;
040import org.opencms.ui.components.CmsErrorDialog;
041import org.opencms.ui.shared.CmsVaadinConstants;
042import org.opencms.util.CmsFileUtil;
043import org.opencms.util.CmsMacroResolver;
044import org.opencms.util.CmsStringUtil;
045
046import javax.servlet.http.HttpServletRequest;
047
048import org.apache.commons.logging.Log;
049
050import com.vaadin.annotations.Theme;
051import com.vaadin.server.VaadinRequest;
052import com.vaadin.server.WrappedSession;
053import com.vaadin.shared.Version;
054import com.vaadin.ui.JavaScript;
055
056/**
057 * Displays the error page.<p>
058 */
059@Theme("opencms")
060public class CmsErrorUI extends A_CmsUI {
061
062    /** The serial version id. */
063    private static final long serialVersionUID = -7274300240145879438L;
064
065    /** Logger instance for this class. */
066    private static final Log LOG = CmsLog.getLog(CmsErrorUI.class);
067
068    /** The throwable session attribute name. */
069    private static final String THROWABLE = "THROWABLE";
070
071    /** The path session attribute name. */
072    private static final String PATH = "PATH";
073
074    /** The error page path fragment. */
075    public static final String ERROR_PAGE_PATH_FRAQUMENT = "errorpage/";
076
077    /** The path to the requested page. */
078    @SuppressWarnings("unused")
079    private String m_requestedPage;
080
081    /** The displayed exception. */
082    private Throwable m_throwable;
083
084    /**
085     * Returns the error bootstrap page HTML.<p>
086     *
087     * @param cms the cms context
088     * @param throwable the throwable
089     * @param request the current request
090     *
091     * @return the error bootstrap page HTML
092     */
093    public static String getBootstrapPage(CmsObject cms, Throwable throwable, HttpServletRequest request) {
094
095        try {
096            setErrorAttributes(cms, throwable, request);
097
098            byte[] pageBytes = CmsFileUtil.readFully(
099                Thread.currentThread().getContextClassLoader().getResourceAsStream(
100                    "org/opencms/ui/error/error-page.html"));
101            String page = new String(pageBytes, "UTF-8");
102            CmsMacroResolver resolver = new CmsMacroResolver();
103            String context = OpenCms.getSystemInfo().getContextPath();
104            String vaadinDir = CmsStringUtil.joinPaths(context, "VAADIN/");
105            String vaadinVersion = Version.getFullVersion();
106            String vaadinServlet = CmsStringUtil.joinPaths(context, "workplace/", ERROR_PAGE_PATH_FRAQUMENT);
107            String vaadinBootstrap = CmsStringUtil.joinPaths(context, "VAADIN/vaadinBootstrap.js");
108
109            resolver.addMacro("loadingHtml", CmsVaadinConstants.LOADING_INDICATOR_HTML);
110            resolver.addMacro("vaadinDir", vaadinDir);
111            resolver.addMacro("vaadinVersion", vaadinVersion);
112            resolver.addMacro("vaadinServlet", vaadinServlet);
113            resolver.addMacro("vaadinBootstrap", vaadinBootstrap);
114            resolver.addMacro("title", "Error page");
115
116            page = resolver.resolveMacros(page);
117            return page;
118        } catch (Exception e) {
119            LOG.error("Failed to display error page.", e);
120            return "<!--Error-->";
121        }
122    }
123
124    /**
125     * Sets the error attributes to the current session.<p>
126     *
127     * @param cms the cms context
128     * @param throwable the throwable
129     * @param request the current request
130     */
131    private static void setErrorAttributes(CmsObject cms, Throwable throwable, HttpServletRequest request) {
132
133        String errorUri = CmsFlexController.getThrowableResourceUri(request);
134        if (errorUri == null) {
135            errorUri = cms.getRequestContext().getUri();
136        }
137
138        // try to get the exception root cause
139        Throwable cause = CmsFlexController.getThrowable(request);
140        if (cause == null) {
141            cause = throwable;
142        }
143
144        request.getSession().setAttribute(THROWABLE, cause);
145        request.getSession().setAttribute(PATH, errorUri);
146    }
147
148    /**
149     * @see com.vaadin.ui.UI#init(com.vaadin.server.VaadinRequest)
150     */
151    @Override
152    protected void init(VaadinRequest request) {
153
154        readErrorAttributes();
155        CmsErrorDialog.showErrorDialog(getErrorMessage(m_throwable), m_throwable, new Runnable() {
156
157            public void run() {
158
159                JavaScript.eval(
160                    "if (window.parent && window.parent."
161                        + CmsLegacyApp.VAR_IS_LEGACY_APP
162                        + ") window.parent.location.reload();");
163            }
164        });
165    }
166
167    /**
168     * Returns the error message to be displayed.<p>
169     *
170     * @param throwable the throwable
171     *
172     * @return the error message to be displayed
173     */
174    private String getErrorMessage(Throwable throwable) {
175
176        StringBuffer result = new StringBuffer(512);
177
178        result.append(
179            CmsVaadinUtils.getMessageText(org.opencms.ui.components.Messages.GUI_ERROR_DIALOG_MESSAGE_0)).append(
180                "<br />");
181
182        // if a localized message is already set as a parameter, append it.
183        result.append(getMessage(throwable));
184
185        return result.toString();
186    }
187
188    /**
189     * Returns the localized Message, if the argument is a CmsException, or
190     * the message otherwise.<p>
191     *
192     * @param t the Throwable to get the message from
193     *
194     * @return returns the localized Message, if the argument is a CmsException, or
195     * the message otherwise
196     */
197    private String getMessage(Throwable t) {
198
199        if ((t instanceof I_CmsThrowable) && (((I_CmsThrowable)t).getMessageContainer() != null)) {
200            StringBuffer result = new StringBuffer(256);
201            if (t instanceof CmsMultiException) {
202                CmsMultiException exc = (CmsMultiException)t;
203                String message = exc.getMessage(getLocale());
204                if (CmsStringUtil.isNotEmpty(message)) {
205                    result.append(message);
206                    result.append("<br />");
207                }
208
209            }
210
211            I_CmsThrowable cmsThrowable = (I_CmsThrowable)t;
212            result.append(cmsThrowable.getLocalizedMessage(getLocale()));
213            return result.toString();
214        } else {
215            String message = t.getMessage();
216            if (CmsStringUtil.isEmptyOrWhitespaceOnly(message)) {
217                // no error message found (e.g. for NPE), provide default message text
218                message = CmsVaadinUtils.getMessageText(Messages.GUI_ERROR_UNKNOWN_0);
219            }
220            return message;
221        }
222    }
223
224    /**
225     * Reads the error attributes from current session.<p>
226     */
227    private void readErrorAttributes() {
228
229        WrappedSession session = getSession().getSession();
230        m_requestedPage = (String)session.getAttribute(PATH);
231        m_throwable = (Throwable)session.getAttribute(THROWABLE);
232
233        // remove the attributes after read to keep the session clean
234        session.removeAttribute(THROWABLE);
235        session.removeAttribute(PATH);
236    }
237}