All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.flex.CmsFlexController Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.flex;

import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.main.CmsLog;
import org.opencms.util.CmsRequestUtil;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;

/**
 * Controller for getting access to the CmsObject, should be used as a
 * request attribute.

* * @since 6.0.0 */ public class CmsFlexController { /** Constant for the controller request attribute name. */ public static final String ATTRIBUTE_NAME = "org.opencms.flex.CmsFlexController"; /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsFlexController.class); /** Set of uncacheable attributes. */ private static Set uncacheableAttributes = new HashSet(); /** The CmsFlexCache where the result will be cached in, required for the dispatcher. */ private CmsFlexCache m_cache; /** The wrapped CmsObject provides JSP with access to the core system. */ private CmsObject m_cmsObject; /** List of wrapped RequestContext info object. */ private List m_flexContextInfoList; /** List of wrapped CmsFlexRequests. */ private List m_flexRequestList; /** List of wrapped CmsFlexResponses. */ private List m_flexResponseList; /** Indicates if this controller is currently in "forward" mode. */ private boolean m_forwardMode; /** Wrapped top request. */ private HttpServletRequest m_req; /** Wrapped top response. */ private HttpServletResponse m_res; /** The CmsResource that was initialized by the original request, required for URI actions. */ private CmsResource m_resource; /** Indicates if the response should be streamed. */ private boolean m_streaming; /** Exception that was caught during inclusion of sub elements. */ private Throwable m_throwable; /** URI of a VFS resource that caused the exception. */ private String m_throwableResourceUri; /** Indicates if the request is the top request. */ private boolean m_top; /** * Creates a new controller form the old one, exchanging just the provided OpenCms user context.

* * @param cms the OpenCms user context for this controller * @param base the base controller */ public CmsFlexController(CmsObject cms, CmsFlexController base) { m_cmsObject = cms; m_resource = base.m_resource; m_cache = base.m_cache; m_req = base.m_req; m_res = base.m_res; m_streaming = base.m_streaming; m_top = base.m_top; m_flexRequestList = base.m_flexRequestList; m_flexResponseList = base.m_flexResponseList; m_flexContextInfoList = base.m_flexContextInfoList; m_forwardMode = base.m_forwardMode; m_throwableResourceUri = base.m_throwableResourceUri; } /** * Default constructor.

* * @param cms the initial CmsObject to wrap in the controller * @param resource the file requested * @param cache the instance of the flex cache * @param req the current request * @param res the current response * @param streaming indicates if the response is streaming * @param top indicates if the response is the top response */ public CmsFlexController( CmsObject cms, CmsResource resource, CmsFlexCache cache, HttpServletRequest req, HttpServletResponse res, boolean streaming, boolean top) { m_cmsObject = cms; m_resource = resource; m_cache = cache; m_req = req; m_res = res; m_streaming = streaming; m_top = top; m_flexRequestList = new Vector(); m_flexResponseList = new Vector(); m_flexContextInfoList = new Vector(); m_forwardMode = false; m_throwableResourceUri = null; } /** * Returns the wrapped CmsObject form the provided request, or null if the * request is not running inside OpenCms.

* * @param req the current request * @return the wrapped CmsObject */ public static CmsObject getCmsObject(ServletRequest req) { CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME); if (controller != null) { return controller.getCmsObject(); } else { return null; } } /** * Returns the controller from the given request, or null if the * request is not running inside OpenCms.

* * @param req the request to get the controller from * * @return the controller from the given request, or null if the request is not running inside OpenCms */ public static CmsFlexController getController(ServletRequest req) { return (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME); } /** * Provides access to a root cause Exception that might have occurred in a complex include scenario.

* * @param req the current request * * @return the root cause exception or null if no root cause exception is available * * @see #getThrowable() */ public static Throwable getThrowable(ServletRequest req) { CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME); if (controller != null) { return controller.getThrowable(); } else { return null; } } /** * Provides access to URI of a VFS resource that caused an exception that might have occurred in a complex include scenario.

* * @param req the current request * * @return to URI of a VFS resource that caused an exception, or null * * @see #getThrowableResourceUri() */ public static String getThrowableResourceUri(ServletRequest req) { CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME); if (controller != null) { return controller.getThrowableResourceUri(); } else { return null; } } /** * Checks if the provided request is running in OpenCms and the current users project is the online project.

* * @param req the current request * * @return true if the request is running in OpenCms and the current users project is * the online project, false otherwise */ public static boolean isCmsOnlineRequest(ServletRequest req) { if (req == null) { return false; } return getController(req).getCmsObject().getRequestContext().getCurrentProject().isOnlineProject(); } /** * Checks if the provided request is running in OpenCms.

* * @param req the current request * * @return true if the request is running in OpenCms, false otherwise */ public static boolean isCmsRequest(ServletRequest req) { return ((req != null) && (req.getAttribute(ATTRIBUTE_NAME) != null)); } /** * Checks if the request has the "If-Modified-Since" header set, and if so, * if the header date value is equal to the provided last modification date.

* * @param req the request to set the "If-Modified-Since" date header from * @param dateLastModified the date to compare the header with * * @return true if the header is set and the header date is equal to the provided date */ public static boolean isNotModifiedSince(HttpServletRequest req, long dateLastModified) { // check if the request contains a last modified header try { long lastModifiedHeader = req.getDateHeader(CmsRequestUtil.HEADER_IF_MODIFIED_SINCE); // if last modified header is set (> -1), compare it to the requested resource return ((lastModifiedHeader > -1) && (((dateLastModified / 1000) * 1000) == lastModifiedHeader)); } catch (Exception ex) { // some clients (e.g. User-Agent: BlackBerry7290/4.1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/111) // send an invalid "If-Modified-Since" header (e.g. in german locale) // which breaks with http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html // this has to be caught because the subsequent request for the 500 error handler // would run into the same exception. LOG.warn( Messages.get().getBundle().key( Messages.ERR_HEADER_IFMODIFIEDSINCE_FORMAT_3, new Object[] { CmsRequestUtil.HEADER_IF_MODIFIED_SINCE, req.getHeader(CmsRequestUtil.HEADER_USER_AGENT), req.getHeader(CmsRequestUtil.HEADER_IF_MODIFIED_SINCE)})); } return false; } /** * Tells the flex controller to never cache the given attribute.

* * @param attributeName the attribute which shouldn't be cached */ public static void registerUncacheableAttribute(String attributeName) { uncacheableAttributes.add(attributeName); } /** * Removes the controller attribute from a request.

* * @param req the request to remove the controller from */ public static void removeController(ServletRequest req) { CmsFlexController controller = (CmsFlexController)req.getAttribute(ATTRIBUTE_NAME); if (controller != null) { controller.clear(); } } /** * Stores the given controller in the given request (using a request attribute).

* * @param req the request where to store the controller in * @param controller the controller to store */ public static void setController(ServletRequest req, CmsFlexController controller) { req.setAttribute(CmsFlexController.ATTRIBUTE_NAME, controller); } /** * Sets the Expires date header for a given http request.

* * Also sets the cache-control: max-age header to the time of the expiration. * A certain upper limit is imposed on the expiration date parameter to ensure the resources are * not cached to long in proxies. This can be controlled by the maxAge parameter. * If maxAge is lower then 0, then a default max age of 86400000 msec (1 day) is used.

* * @param res the response to set the "Expires" date header for * @param maxAge maximum amount of time in milliseconds the response remains valid * @param dateExpires the date to set (if this is not in the future, it is ignored) */ public static void setDateExpiresHeader(HttpServletResponse res, long dateExpires, long maxAge) { long now = System.currentTimeMillis(); if ((dateExpires > now) && (dateExpires != CmsResource.DATE_EXPIRED_DEFAULT)) { // important: many caches (browsers or proxy) use the "Expires" header // to avoid re-loading of pages that are not expired // while this is right in general, no changes before the expiration date // will be displayed // therefore it is better to not use an expiration to far in the future // if no valid max age is set, restrict it to 24 hrs if (maxAge < 0L) { maxAge = 86400000; } if ((dateExpires - now) > maxAge) { // set "Expires" header max one day into the future dateExpires = now + maxAge; } res.setDateHeader(CmsRequestUtil.HEADER_EXPIRES, dateExpires); // setting the "Expires" header only is not sufficient - even expired documents seems to be cached // therefore, the "cache-control: max-age" is also set res.setHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MAX_AGE + (maxAge / 1000L)); } } /** * Sets the "last modified" date header for a given http request.

* * @param res the response to set the "last modified" date header for * @param dateLastModified the date to set (if this is lower then 0, the current time is set) */ public static void setDateLastModifiedHeader(HttpServletResponse res, long dateLastModified) { if (dateLastModified > -1) { // set date last modified header (precision is only second, not millisecond res.setDateHeader(CmsRequestUtil.HEADER_LAST_MODIFIED, (dateLastModified / 1000) * 1000); } else { // this resource can not be optimized for "last modified", use current time as header res.setDateHeader(CmsRequestUtil.HEADER_LAST_MODIFIED, System.currentTimeMillis()); // avoiding issues with IE8+ res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, "public, max-age=0"); } } /** * Clears all data of this controller.

*/ public void clear() { if (m_flexRequestList != null) { m_flexRequestList.clear(); } m_flexRequestList = null; if (m_flexResponseList != null) { m_flexResponseList.clear(); } m_flexResponseList = null; if (m_req != null) { m_req.removeAttribute(ATTRIBUTE_NAME); } m_req = null; m_res = null; m_cmsObject = null; m_resource = null; m_cache = null; m_throwable = null; } /** * Returns the CmsFlexCache instance where all results from this request will be cached in.

* * This is public so that pages like the Flex Cache Administration page * have a way to access the cache object.

* * @return the CmsFlexCache instance where all results from this request will be cached in */ public CmsFlexCache getCmsCache() { return m_cache; } /** * Returns the wrapped CmsObject.

* * @return the wrapped CmsObject */ public CmsObject getCmsObject() { return m_cmsObject; } /** * This method provides access to the top-level CmsResource of the request * which is of a type that supports the FlexCache, * i.e. usually the CmsFile that is identical to the file uri requested by the user, * not he current included element.

* * @return the requested top-level CmsFile */ public CmsResource getCmsResource() { return m_resource; } /** * Returns the current flex request.

* * @return the current flex request */ public CmsFlexRequest getCurrentRequest() { return m_flexRequestList.get(m_flexRequestList.size() - 1); } /** * Returns the current flex response.

* * @return the current flex response */ public CmsFlexResponse getCurrentResponse() { return m_flexResponseList.get(m_flexResponseList.size() - 1); } /** * Returns the combined "expires" date for all resources read during this request.

* * @return the combined "expires" date for all resources read during this request */ public long getDateExpires() { int pos = m_flexContextInfoList.size() - 1; if (pos < 0) { // ensure a valid position is used return CmsResource.DATE_EXPIRED_DEFAULT; } return (m_flexContextInfoList.get(pos)).getDateExpires(); } /** * Returns the combined "last modified" date for all resources read during this request.

* * @return the combined "last modified" date for all resources read during this request */ public long getDateLastModified() { int pos = m_flexContextInfoList.size() - 1; if (pos < 0) { // ensure a valid position is used return CmsResource.DATE_RELEASED_DEFAULT; } return (m_flexContextInfoList.get(pos)).getDateLastModified(); } /** * Returns the size of the response stack.

* * @return the size of the response stack */ public int getResponseStackSize() { return m_flexResponseList.size(); } /** * Returns an exception (Throwable) that was caught during inclusion of sub elements, * or null if no exceptions where thrown in sub elements.

* * @return an exception (Throwable) that was caught during inclusion of sub elements */ public Throwable getThrowable() { return m_throwable; } /** * Returns the URI of a VFS resource that caused the exception that was caught during inclusion of sub elements, * might return null if no URI information was available for the exception.

* * @return the URI of a VFS resource that caused the exception that was caught during inclusion of sub elements */ public String getThrowableResourceUri() { return m_throwableResourceUri; } /** * Returns the current http request.

* * @return the current http request */ public HttpServletRequest getTopRequest() { return m_req; } /** * Returns the current http response.

* * @return the current http response */ public HttpServletResponse getTopResponse() { return m_res; } /** * Returns true if the controller does not yet contain any requests.

* * @return true if the controller does not yet contain any requests */ public boolean isEmptyRequestList() { return (m_flexRequestList != null) && m_flexRequestList.isEmpty(); } /** * Returns true if this controller is currently in "forward" mode.

* * @return true if this controller is currently in "forward" mode */ public boolean isForwardMode() { return m_forwardMode; } /** * Returns true if the generated output of the response should * be written to the stream directly.

* * @return true if the generated output of the response should be written to the stream directly */ public boolean isStreaming() { return m_streaming; } /** * Returns true if this controller was generated as top level controller.

* * If a resource (e.g. a JSP) is processed and it's content is included in * another resource, then this will be false. * * @return true if this controller was generated as top level controller * * @see org.opencms.loader.I_CmsResourceLoader#dump(CmsObject, CmsResource, String, java.util.Locale, HttpServletRequest, HttpServletResponse) * @see org.opencms.jsp.CmsJspActionElement#getContent(String) */ public boolean isTop() { return m_top; } /** * Removes the topmost request/response pair from the stack.

*/ public void pop() { if ((m_flexRequestList != null) && !m_flexRequestList.isEmpty()) { m_flexRequestList.remove(m_flexRequestList.size() - 1); } if ((m_flexResponseList != null) && !m_flexRequestList.isEmpty()) { m_flexResponseList.remove(m_flexResponseList.size() - 1); } if ((m_flexContextInfoList != null) && !m_flexContextInfoList.isEmpty()) { CmsFlexRequestContextInfo info = m_flexContextInfoList.remove(m_flexContextInfoList.size() - 1); if (m_flexContextInfoList.size() > 0) { (m_flexContextInfoList.get(0)).merge(info); updateRequestContextInfo(); } } } /** * Adds another flex request/response pair to the stack.

* * @param req the request to add * @param res the response to add */ public void push(CmsFlexRequest req, CmsFlexResponse res) { m_flexRequestList.add(req); m_flexResponseList.add(res); m_flexContextInfoList.add(new CmsFlexRequestContextInfo()); updateRequestContextInfo(); } /** * Removes request attributes which shouldn't be cached in flex cache entries from a map.

* * @param attributeMap the map of attributes */ public void removeUncacheableAttributes(Map attributeMap) { for (String uncacheableAttribute : uncacheableAttributes) { attributeMap.remove(uncacheableAttribute); } attributeMap.remove(CmsFlexController.ATTRIBUTE_NAME); attributeMap.remove(CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE); } /** * Sets the value of the "forward mode" flag.

* * @param value the forward mode to set */ public void setForwardMode(boolean value) { m_forwardMode = value; } /** * Sets an exception (Throwable) that was caught during inclusion of sub elements.

* * If another exception is already set in this controller, then the additional exception * is ignored.

* * @param throwable the exception (Throwable) to set * @param resource the URI of the VFS resource the error occurred on (might be null if unknown) * * @return the exception stored in the controller */ public Throwable setThrowable(Throwable throwable, String resource) { if (m_throwable == null) { m_throwable = throwable; m_throwableResourceUri = resource; } else { if (LOG.isDebugEnabled()) { if (resource != null) { LOG.debug( Messages.get().getBundle().key(Messages.LOG_FLEXCONTROLLER_IGNORED_EXCEPTION_1, resource)); } else { LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCONTROLLER_IGNORED_EXCEPTION_0)); } } } return m_throwable; } /** * Puts the response in a suspended state.

*/ public void suspendFlexResponse() { for (int i = 0; i < m_flexResponseList.size(); i++) { CmsFlexResponse res = m_flexResponseList.get(i); res.setSuspended(true); } } /** * Updates the "last modified" date and the "expires" date * for all resources read during this request with the given values.

* * The currently stored value for "last modified" is only updated with the new value if * the new value is either larger (i.e. newer) then the stored value, * or if the new value is less then zero, which indicates that the "last modified" * optimization can not be used because the element is dynamic.

* * The stored "expires" value is only updated if the new value is smaller * then the stored value.

* * @param dateLastModified the value to update the "last modified" date with * @param dateExpires the value to update the "expires" date with */ public void updateDates(long dateLastModified, long dateExpires) { int pos = m_flexContextInfoList.size() - 1; if (pos < 0) { // ensure a valid position is used return; } (m_flexContextInfoList.get(pos)).updateDates(dateLastModified, dateExpires); } /** * Updates the context info of the request context.

*/ private void updateRequestContextInfo() { if ((m_flexContextInfoList != null) && !m_flexContextInfoList.isEmpty()) { m_cmsObject.getRequestContext().setAttribute( CmsRequestUtil.HEADER_LAST_MODIFIED, m_flexContextInfoList.get(m_flexContextInfoList.size() - 1)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy