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 GmbH & Co. KG, 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.jsp;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsRequestContext;
032import org.opencms.flex.CmsFlexController;
033import org.opencms.i18n.CmsMessageContainer;
034import org.opencms.main.CmsLog;
035import org.opencms.main.CmsRuntimeException;
036import org.opencms.util.CmsRequestUtil;
037
038import javax.servlet.http.HttpServletRequest;
039import javax.servlet.http.HttpServletResponse;
040import javax.servlet.jsp.PageContext;
041
042import org.apache.commons.logging.Log;
043
044/**
045 * Superclass for OpenCms JSP beans that provides convient access
046 * to OpenCms core and VFS functionality.<p>
047 *
048 * If you have large chunks of code on your JSP that you want to
049 * move to a Class file, consider creating a subclass of this bean.
050 *
051 * Initialize this bean at the beginning of your JSP like this:
052 * <pre>
053 * &lt;jsp:useBean id="cmsbean" class="org.opencms.jsp.CmsJspBean"&gt;
054 * &lt% cmsbean.init(pageContext, request, response); %&gt;
055 * &lt;/jsp:useBean&gt;
056 * </pre>
057 * <p>
058 *
059 * @since 6.0.0
060 */
061public class CmsJspBean {
062
063    /** The log object for this class. */
064    private static final Log LOG = CmsLog.getLog(CmsJspBean.class);
065
066    /** JSP page context. */
067    private PageContext m_context;
068
069    /** OpenCms core CmsObject. */
070    private CmsFlexController m_controller;
071
072    /** Flag to indicate that this bean was properly initialized. */
073    private boolean m_isNotInitialized;
074
075    /** Flag to indicate if we want default or custom Exception handling. */
076    private boolean m_isSupressingExceptions;
077
078    /** OpenCms JSP request. */
079    private HttpServletRequest m_request;
080
081    /** OpenCms JSP response. */
082    private HttpServletResponse m_response;
083
084    /**
085     * Empty constructor, required for every JavaBean.<p>
086     */
087    public CmsJspBean() {
088
089        // noop, call init() to get going
090        m_isSupressingExceptions = true;
091        m_isNotInitialized = true;
092    }
093
094    /**
095     * Returns the CmsObject from the wrapped request.<p>
096     *
097     * This is a convenience method in case you need access to
098     * the CmsObject in your JSP scriplets.<p>
099     *
100     * @return the CmsObject from the wrapped request
101     */
102    public CmsObject getCmsObject() {
103
104        if (m_isNotInitialized) {
105            return null;
106        }
107        return m_controller.getCmsObject();
108    }
109
110    /**
111     * Returns the JSP page context this bean was initialized with.<p>
112     *
113     * @return the JSP page context this bean was initialized with
114     */
115    public PageContext getJspContext() {
116
117        return m_context;
118    }
119
120    /**
121     * Returns the request this bean was initialized with.<p>
122     *
123     * @return the request this bean was initialized with
124     */
125    public HttpServletRequest getRequest() {
126
127        return m_request;
128    }
129
130    /**
131     * Returns the current users OpenCms request context.<p>
132     *
133     * @return the current users OpenCms request context
134     */
135    public CmsRequestContext getRequestContext() {
136
137        return getCmsObject().getRequestContext();
138    }
139
140    /**
141     * Returns the response wrapped by this element.<p>
142     *
143     * @return the response wrapped by this element
144     */
145    public HttpServletResponse getResponse() {
146
147        return m_response;
148    }
149
150    /**
151     * Initialize this bean with the current page context, request and response.<p>
152     *
153     * It is required to call one of the init() methods before you can use the
154     * instance of this bean.
155     *
156     * @param context the JSP page context object
157     * @param req the JSP request
158     * @param res the JSP response
159     */
160    public void init(PageContext context, HttpServletRequest req, HttpServletResponse res) {
161
162        m_controller = CmsFlexController.getController(req);
163        if (m_controller == null) {
164            handleMissingFlexController();
165        }
166        m_context = context;
167        m_request = req;
168        m_response = res;
169        m_isNotInitialized = false;
170    }
171
172    /**
173     * Returns <code>true</code> if Exceptions are handled by the class instance and suppressed on the
174     * output page, or <code>false</code> if they will be thrown and have to be handled by the calling class.<p>
175     *
176     * The default is <code>true</code>.
177     * If set to <code>false</code> Exceptions that occur internally will be wrapped into
178     * a RuntimeException and thrown to the calling class instance.<p>
179     *
180     * @return <code>true</code> if Exceptions are suppressed, or
181     *      <code>false</code> if they will be thrown and have to be handled by the calling class
182     */
183    public boolean isSupressingExceptions() {
184
185        return m_isSupressingExceptions;
186    }
187
188    /**
189     * Sets the content type for the HTTP response.<p>
190     *
191     * This method is required since JSP's are handled in a special way for included template elements,
192     * so {@link javax.servlet.ServletResponse#setContentType(java.lang.String)} won't work.<p>
193     *
194     * Please note that the content type set this way is never cached in the Flex cache,
195     * so you must make sure to not cache the element when you use this method.<p>
196     *
197     * @param type the type to set
198     *
199     * @see javax.servlet.ServletResponse#setContentType(java.lang.String)
200     */
201    public void setContentType(String type) {
202
203        // set the content type on the top level response
204        m_controller.getTopResponse().setContentType(type);
205    }
206
207    /**
208     * Sets the status code for the HTTP response.<p>
209     *
210     * This method is required since JSP's are handled in a special way for included template elements,
211     * so {@link javax.servlet.http.HttpServletResponseWrapper#setStatus(int)} won't work.<p>
212     *
213     * Please note that the status code set this way is never cached in the Flex cache,
214     * so you must make sure to not cache the element when you use this method.<p>
215     *
216     * @param status the status code to set
217     *
218     * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int)
219     */
220    public void setStatus(int status) {
221
222        // use the request attribute to store the status
223        m_request.setAttribute(CmsRequestUtil.ATTRIBUTE_ERRORCODE, new Integer(status));
224    }
225
226    /**
227     * Controls if Exceptions that occur in methods of this class are suppressed (true)
228     * or not (false).<p>
229     *
230     * The default is <code>true</code>. If set to <code>false</code> all Exceptions that
231     * occur internally will be wrapped into a RuntimeException and thrown to the calling
232     * class instance.<p>
233     *
234     * @param value the value to set the Exception handing to
235     */
236    public void setSupressingExceptions(boolean value) {
237
238        m_isSupressingExceptions = value;
239    }
240
241    /**
242     * Returns the Flex controller derived from the request this bean was initialized with.<p>
243     *
244     * This is protected since the CmsFlexController this is really an internal OpenCms
245     * helper function, not part of the public OpenCms API. It must not be used on JSP pages,
246     * only from subclasses of this bean.<p>
247     *
248     * @return the Flex controller derived from the request this bean was initialized with
249     */
250    protected CmsFlexController getController() {
251
252        return m_controller;
253    }
254
255    /**
256     * Internally localizes the given <code>CmsMessageContainer</code> to a String. <p>
257     *
258     * If the user request context is at hand, the user's locale will be chosen. If
259     * no user request context is available, the default locale is used. <p>
260     *
261     * @param container the message container that allows localization of the represented message.
262     *
263     * @return the message String of the container argument localized to the user's locale (if available) or
264     *         to the default locale.
265     */
266    protected String getMessage(CmsMessageContainer container) {
267
268        CmsObject cms = getCmsObject();
269        String result;
270        if ((cms == null) || (cms.getRequestContext().getLocale() == null)) {
271            result = container.key();
272        } else {
273            result = container.key(cms.getRequestContext().getLocale());
274        }
275        return result;
276    }
277
278    /**
279     * Handles any exception that might occur in the context of this element to
280     * ensure that templates are not disturbed.<p>
281     *
282     * @param t the Throwable that was caught
283     */
284    protected void handleException(Throwable t) {
285
286        if (LOG.isErrorEnabled()) {
287            LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_JSP_BEAN_0), t);
288        }
289        if (!(m_isSupressingExceptions || getRequestContext().getCurrentProject().isOnlineProject())) {
290            if (LOG.isDebugEnabled()) {
291                // no stack trace needed since it was already logged with the "error" log message above
292                LOG.debug(
293                    Messages.get().getBundle().key(Messages.LOG_DEBUG_INTERRUPTED_EXCEPTION_1, getClass().getName()));
294            }
295            String uri = null;
296            Throwable u = getController().getThrowable();
297            if (u != null) {
298                uri = getController().getThrowableResourceUri();
299            } else {
300                uri = getRequestContext().getUri();
301            }
302            throw new CmsRuntimeException(
303                Messages.get().container(Messages.ERR_RUNTIME_1, (uri != null) ? uri : getClass().getName()),
304                t);
305        }
306    }
307
308    /**
309     * This method is called when the flex controller can not be found during initialization.<p>
310     *
311     * Override this if you are reusing old workplace classes in a context where no flex controller is available.
312     */
313    protected void handleMissingFlexController() {
314
315        // controller not found - this request was not initialized properly
316        throw new CmsRuntimeException(
317            Messages.get().container(Messages.ERR_MISSING_CMS_CONTROLLER_1, CmsJspBean.class.getName()));
318    }
319
320    /**
321     * Returns true if this bean has not been initialized (i.e. init() has not been called so far), false otherwise.<p>
322     *
323     * @return true if this bean has not been initialized
324     */
325    protected boolean isNotInitialized() {
326
327        return m_isNotInitialized;
328    }
329}