/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (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, 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.jsp.util;
import org.opencms.ade.configuration.CmsADEConfigData;
import org.opencms.ade.configuration.CmsFunctionReference;
import org.opencms.ade.detailpage.CmsDetailPageInfo;
import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsRequestContext;
import org.opencms.file.CmsResource;
import org.opencms.flex.CmsFlexController;
import org.opencms.jsp.CmsJspBean;
import org.opencms.jsp.Messages;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.CmsRuntimeException;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsUUID;
import org.opencms.xml.containerpage.CmsContainerBean;
import org.opencms.xml.containerpage.CmsContainerElementBean;
import org.opencms.xml.containerpage.CmsContainerPageBean;
import org.opencms.xml.containerpage.CmsDynamicFunctionBean;
import org.opencms.xml.containerpage.CmsDynamicFunctionParser;
import org.opencms.xml.content.CmsXmlContent;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletRequest;
import org.apache.commons.logging.Log;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
/**
* Allows convenient access to the most important OpenCms functions on a JSP page,
* indented to be used from a JSP with the JSTL or EL.<p>
*
* This bean is available by default in the context of an OpenCms managed JSP.<p>
*
* @since 8.0
*/
public final class CmsJspStandardContextBean {
/** The attribute name of the cms object.*/
public static final String ATTRIBUTE_CMS_OBJECT = "__cmsObject";
/** The attribute name of the standard JSP context bean. */
public static final String ATTRIBUTE_NAME = "cms";
/** The logger instance for this class. */
protected static final Log LOG = CmsLog.getLog(CmsJspStandardContextBean.class);
/** OpenCms user context. */
protected CmsObject m_cms;
/** The container the currently rendered element is part of. */
private CmsContainerBean m_container;
/** The current detail content resource if available. */
private CmsResource m_detailContentResource;
/** Flag to indicate if element was just edited. */
private boolean m_edited;
/** The currently rendered element. */
private CmsContainerElementBean m_element;
/** Cached object for the EL 'function' accessor. */
private Object m_function;
/** The currently displayed container page. */
private CmsContainerPageBean m_page;
/** The VFS content access bean. */
private CmsJspVfsAccessBean m_vfsBean;
/**
* Creates an empty instance.<p>
*/
private CmsJspStandardContextBean() {
// NOOP
}
/**
* Creates a new standard JSP context bean.
*
* @param req the current servlet request
*/
private CmsJspStandardContextBean(ServletRequest req) {
CmsFlexController controller = CmsFlexController.getController(req);
CmsObject cms;
if (controller != null) {
cms = controller.getCmsObject();
} else {
cms = (CmsObject)req.getAttribute(ATTRIBUTE_CMS_OBJECT);
}
if (cms == null) {
// cms object unavailable - this request was not initialized properly
throw new CmsRuntimeException(Messages.get().container(
Messages.ERR_MISSING_CMS_CONTROLLER_1,
CmsJspBean.class.getName()));
}
updateCmsObject(cms);
m_detailContentResource = CmsDetailPageResourceHandler.getDetailResource(req);
}
/**
* Creates a new instance of the standard JSP context bean.<p>
*
* To prevent multiple creations of the bean during a request, the OpenCms request context
* attributes are used to cache the created VFS access utility bean.<p>
*
* @param req the current servlet request
*
* @return a new instance of the standard JSP context bean
*/
public static CmsJspStandardContextBean getInstance(ServletRequest req) {
Object attribute = req.getAttribute(ATTRIBUTE_NAME);
CmsJspStandardContextBean result;
if ((attribute != null) && (attribute instanceof CmsJspStandardContextBean)) {
result = (CmsJspStandardContextBean)attribute;
} else {
result = new CmsJspStandardContextBean(req);
req.setAttribute(ATTRIBUTE_NAME, result);
}
return result;
}
/**
* Returns a copy of this JSP context bean.<p>
*
* @return a copy of this JSP context bean
*/
public CmsJspStandardContextBean createCopy() {
CmsJspStandardContextBean result = new CmsJspStandardContextBean();
result.m_container = getContainer();
if (getDetailContent() != null) {
result.m_detailContentResource = getDetailContent().getCopy();
}
result.m_element = getElement();
result.m_page = getPage();
return result;
}
/**
* Returns a caching hash specific to the element, it's properties and the current container width.<p>
*
* @return the caching hash
*/
public String elementCachingHash() {
if ((m_element != null) && (m_container != null)) {
return m_element.editorHash()
+ "w:"
+ m_container.getWidth()
+ "cName:"
+ m_container.getName()
+ "cType:"
+ m_container.getType();
}
return "";
}
/**
* Returns the container the currently rendered element is part of.<p>
*
* @return the currently the currently rendered element is part of
*/
public CmsContainerBean getContainer() {
return m_container;
}
/**
* Returns the current detail content, or <code>null</code> if no detail content is requested.<p>
*
* @return the current detail content, or <code>null</code> if no detail content is requested.<p>
*/
public CmsResource getDetailContent() {
return m_detailContentResource;
}
/**
* Returns the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p>
*
* @return the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p>
*/
public CmsUUID getDetailContentId() {
return m_detailContentResource == null ? null : m_detailContentResource.getStructureId();
}
/**
* Returns the detail content site path. Returns <code>null</code> if not available.<p>
*
* @return the detail content site path
*/
public String getDetailContentSitePath() {
return ((m_cms == null) || (m_detailContentResource == null))
? null
: m_cms.getSitePath(m_detailContentResource);
}
/**
* Returns the currently rendered element.<p>
*
* @return the currently rendered element
*/
public CmsContainerElementBean getElement() {
return m_element;
}
/**
* Returns a map which allows access to dynamic function beans using the JSP EL.<p>
*
* When given a key, the returned map will look up the corresponding dynamic function in the module configuration.<p>
*
* @return a map which allows access to dynamic function beans
*/
public Object getFunction() {
if (m_function != null) {
return m_function;
}
MapMaker mm = new MapMaker();
m_function = mm.makeComputingMap(new Function<String, Object>() {
public Object apply(String key) {
try {
CmsDynamicFunctionBean dynamicFunction = readDynamicFunctionBean(key);
CmsDynamicFunctionBeanWrapper wrapper = new CmsDynamicFunctionBeanWrapper(m_cms, dynamicFunction);
return wrapper;
} catch (CmsException e) {
return new CmsDynamicFunctionBeanWrapper(m_cms, null);
}
}
});
return m_function;
}
/**
* Returns a lazy map which computes the detail page link as a value when given the name of a (named) dynamic function
* as a key.<p>
*
* @return a lazy map for computing function detail page links
*/
public Map<String, String> getFunctionDetail() {
MapMaker mm = new MapMaker();
return mm.makeComputingMap(new Function<String, String>() {
public String apply(String key) {
String detailType = CmsDetailPageInfo.FUNCTION_PREFIX + key;
CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
m_cms,
m_cms.addSiteRoot(m_cms.getRequestContext().getUri()));
List<CmsDetailPageInfo> detailPages = config.getDetailPagesForType(detailType);
if ((detailPages == null) || (detailPages.size() == 0)) {
return "";
}
CmsDetailPageInfo mainDetailPage = detailPages.get(0);
CmsUUID id = mainDetailPage.getId();
CmsResource detailRes;
try {
detailRes = m_cms.readResource(id);
return OpenCms.getLinkManager().substituteLink(m_cms, detailRes);
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
return "";
}
}
});
}
/**
* Returns a lazy map which creates a wrapper object for a dynamic function format when given an XML content
* as a key.<p>
*
* @return a lazy map for accessing function formats for a content
*/
public Map<CmsJspContentAccessBean, CmsDynamicFunctionFormatWrapper> getFunctionFormatFromContent() {
MapMaker mm = new MapMaker();
return mm.makeComputingMap(new Function<CmsJspContentAccessBean, CmsDynamicFunctionFormatWrapper>() {
public CmsDynamicFunctionFormatWrapper apply(CmsJspContentAccessBean contentAccess) {
CmsXmlContent content = (CmsXmlContent)(contentAccess.getRawContent());
CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser();
CmsDynamicFunctionBean functionBean = null;
try {
functionBean = parser.parseFunctionBean(m_cms, content);
} catch (CmsException e) {
return new CmsDynamicFunctionFormatWrapper(m_cms, null);
}
String type = getContainer().getType();
String width = getContainer().getWidth();
int widthNum = -1;
try {
widthNum = Integer.parseInt(width);
} catch (NumberFormatException e) {
// NOOP
}
CmsDynamicFunctionBean.Format format = functionBean.getFormatForContainer(m_cms, type, widthNum);
CmsDynamicFunctionFormatWrapper wrapper = new CmsDynamicFunctionFormatWrapper(m_cms, format);
return wrapper;
}
});
}
/**
* Returns the current locale.<p>
*
* @return the current locale
*/
public Locale getLocale() {
return getRequestContext().getLocale();
}
/**
* Returns the currently displayed container page.<p>
*
* @return the currently displayed container page
*/
public CmsContainerPageBean getPage() {
return m_page;
}
/**
* Returns the request context.<p>
*
* @return the request context
*/
public CmsRequestContext getRequestContext() {
return m_cms.getRequestContext();
}
/**
* Returns the subsite path for the currently requested URI.<p>
*
* @return the subsite path
*/
public String getSubSitePath() {
return m_cms.getRequestContext().removeSiteRoot(
OpenCms.getADEManager().getSubSiteRoot(m_cms, m_cms.getRequestContext().getRootUri()));
}
/**
* Returns an initialized VFS access bean.<p>
*
* @return an initialized VFS access bean
*/
public CmsJspVfsAccessBean getVfs() {
if (m_vfsBean == null) {
// create a new VVFS access bean
m_vfsBean = CmsJspVfsAccessBean.create(m_cms);
}
return m_vfsBean;
}
/**
* Returns the workplace locale from the current user's settings.<p>
*
* @return returns the workplace locale from the current user's settings
*/
public Locale getWorkplaceLocale() {
return OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
}
/**
* Checks whether a detail page is available for the container element.<p>
*
* @return true if there is a detail page for the container element
*/
public boolean isDetailPageAvailable() {
if (m_cms == null) {
return false;
}
CmsContainerElementBean element = getElement();
if (element == null) {
return false;
}
if (element.isInMemoryOnly()) {
return false;
}
CmsResource res = element.getResource();
if (res == null) {
return false;
}
try {
String detailPage = OpenCms.getADEManager().getDetailPageFinder().getDetailPage(
m_cms,
res.getRootPath(),
m_cms.getRequestContext().getUri());
return detailPage != null;
} catch (CmsException e) {
LOG.warn(e.getLocalizedMessage(), e);
return false;
}
}
/**
* Returns <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise.<p>
*
* Same as to check if {@link #getDetailContent()} is <code>null</code>.<p>
*
* @return <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise
*/
public boolean isDetailRequest() {
return m_detailContentResource != null;
}
/**
* Returns the flag to indicate if in drag and drop mode.<p>
*
* @return <code>true</code> if in drag and drop mode
*/
public boolean isEdited() {
return m_edited;
}
/**
* Sets the container the currently rendered element is part of.<p>
*
* @param container the container the currently rendered element is part of
*/
public void setContainer(CmsContainerBean container) {
m_container = container;
}
/**
* Sets the flag to indicate if in drag and drop mode.<p>
*
* @param edited <code>true</code> if in drag and drop mode
*/
public void setEdited(boolean edited) {
m_edited = edited;
}
/**
* Sets the currently rendered element.<p>
*
* @param element the currently rendered element to set
*/
public void setElement(CmsContainerElementBean element) {
m_element = element;
}
/**
* Sets the currently displayed container page.<p>
*
* @param page the currently displayed container page to set
*/
public void setPage(CmsContainerPageBean page) {
m_page = page;
}
/**
* Updates the internally stored OpenCms user context.<p>
*
* @param cms the new OpenCms user context
*/
public void updateCmsObject(CmsObject cms) {
try {
m_cms = OpenCms.initCmsObject(cms);
} catch (CmsException e) {
// should not happen
m_cms = cms;
}
}
/**
* Reads a dynamic function bean, given its name in the module configuration.<p>
*
* @param configuredName the name of the dynamic function in the module configuration
* @return the dynamic function bean for the dynamic function configured under that name
*
* @throws CmsException if something goes wrong
*/
protected CmsDynamicFunctionBean readDynamicFunctionBean(String configuredName) throws CmsException {
CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
m_cms,
m_cms.addSiteRoot(m_cms.getRequestContext().getUri()));
CmsFunctionReference functionRef = config.getFunctionReference(configuredName);
if (functionRef == null) {
return null;
}
CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser();
CmsResource functionResource = m_cms.readResource(functionRef.getStructureId());
CmsDynamicFunctionBean result = parser.parseFunctionBean(m_cms, functionResource);
return result;
}
}