/*
* 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 GmbH, 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;
import org.opencms.ade.configuration.CmsADEConfigData;
import org.opencms.ade.configuration.CmsResourceTypeConfig;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.history.CmsHistoryResourceHandler;
import org.opencms.file.types.CmsResourceTypeXmlContent;
import org.opencms.flex.CmsFlexController;
import org.opencms.i18n.CmsEncoder;
import org.opencms.json.JSONArray;
import org.opencms.json.JSONException;
import org.opencms.json.JSONObject;
import org.opencms.jsp.util.CmsJspStandardContextBean;
import org.opencms.loader.CmsLoaderException;
import org.opencms.main.CmsException;
import org.opencms.main.CmsIllegalStateException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsPermissionSet;
import org.opencms.util.CmsRequestUtil;
import org.opencms.util.CmsStringUtil;
import org.opencms.workplace.CmsWorkplaceMessages;
import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
import org.opencms.workplace.explorer.CmsResourceUtil;
import org.opencms.xml.CmsXmlContentDefinition;
import org.opencms.xml.CmsXmlException;
import org.opencms.xml.containerpage.CmsADESessionCache;
import org.opencms.xml.containerpage.CmsContainerBean;
import org.opencms.xml.containerpage.CmsContainerElementBean;
import org.opencms.xml.containerpage.CmsContainerPageBean;
import org.opencms.xml.containerpage.CmsFormatterBean;
import org.opencms.xml.containerpage.CmsFormatterConfiguration;
import org.opencms.xml.containerpage.CmsGroupContainerBean;
import org.opencms.xml.containerpage.CmsXmlContainerPage;
import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
import org.opencms.xml.containerpage.CmsXmlGroupContainer;
import org.opencms.xml.containerpage.CmsXmlGroupContainerFactory;
import org.opencms.xml.content.CmsXmlContentProperty;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.commons.logging.Log;
/**
* Provides access to the page container elements.<p>
*
* @since 8.0
*/
public class CmsJspTagContainer extends TagSupport {
/** Json property name constants for containers. */
public enum JsonContainer {
/** The list of elements. */
elements,
/** Flag for the detail view container. */
isDetailView,
/** The max allowed number of elements in the container. */
maxElem,
/** The container name. */
name,
/** The container type. */
type,
/** The container width. */
width;
}
/** HTML class used to identify container elements. */
public static final String CLASS_CONTAINER_ELEMENT_END_MARKER = "cms_ade_element_end";
/** HTML class used to identify container elements. */
public static final String CLASS_CONTAINER_ELEMENT_START_MARKER = "cms_ade_element_start";
/** HTML class used to identify error message for elements where rendering failed to render. */
public static final String CLASS_ELEMENT_ERROR = "cms_ade_element_error";
/** HTML class used to identify group container elements. */
public static final String CLASS_GROUP_CONTAINER_ELEMENT_MARKER = "cms_ade_groupcontainer";
/** Default number of max elements in the container in case no value has been set. */
public static final String DEFAULT_MAX_ELEMENTS = "100";
/** Key used to write container data into the javascript window object. */
public static final String KEY_CONTAINER_DATA = "org_opencms_ade_containerpage_containers";
/** The create no tag attribute value constant. */
private static final String CREATE_NO_TAG = "none";
/** The default tag name constant. */
private static final String DEFAULT_TAG_NAME = "div";
/** The log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsJspTagContainer.class);
/** Serial version UID required for safe serialisation. */
private static final long serialVersionUID = -1228397990961282556L;
/** The detail-view attribute value. */
private boolean m_detailView;
/** The maxElements attribute value. */
private String m_maxElements;
/** The name attribute value. */
private String m_name;
/** The tag attribute value. */
private String m_tag;
/** The class attribute value. */
private String m_tagClass;
/** The type attribute value. */
private String m_type;
/** The container width as a string. */
private String m_width;
/**
* Creates a new data tag for the given container.<p>
*
* @param container the container to get the data tag for
* @param widthStr the width of the container as a string
* @param isDetailView true if this container is currently being used for the detail view
*
* @return html data tag for the given container
*
* @throws JSONException if there is a problem with JSON manipulation
*/
protected static String getContainerDataTag(CmsContainerBean container, String widthStr, boolean isDetailView)
throws JSONException {
// add container data for the editor
JSONObject jsonContainer = new JSONObject();
jsonContainer.put(CmsContainerJsonKeys.NAME, container.getName());
jsonContainer.put(CmsContainerJsonKeys.TYPE, container.getType());
jsonContainer.put(CmsContainerJsonKeys.MAXELEMENTS, container.getMaxElements());
jsonContainer.put(CmsContainerJsonKeys.DETAILVIEW, isDetailView);
int width = -1;
try {
if (widthStr != null) {
width = Integer.parseInt(widthStr);
}
} catch (NumberFormatException e) {
//ignore; set width to -1
}
jsonContainer.put(CmsContainerJsonKeys.WIDTH, width);
JSONArray jsonElements = new JSONArray();
for (CmsContainerElementBean element : container.getElements()) {
jsonElements.put(element.editorHash());
}
jsonContainer.put(CmsContainerJsonKeys.ELEMENTS, jsonElements);
// the container meta data is added to the javascript window object by the following tag, used within the container-page editor
return new StringBuffer("<script type=\"text/javascript\">if (").append(KEY_CONTAINER_DATA).append("!=null) {").append(
KEY_CONTAINER_DATA).append(".push(").append(jsonContainer.toString()).append("); } </script>").toString();
}
/**
* Creates the closing tag for the container.<p>
*
* @param tagName the tag name
*
* @return the closing tag
*/
protected static String getTagClose(String tagName) {
return "</" + tagName + ">";
}
/**
* Creates the opening tag for the container assigning the appropriate id and class attributes.<p>
*
* @param tagName the tag name
* @param containerName the container name used as id attribute value
* @param tagClass the tag class attribute value
*
* @return the opening tag
*/
protected static String getTagOpen(String tagName, String containerName, String tagClass) {
String classAttr = CmsStringUtil.isEmptyOrWhitespaceOnly(tagClass) ? "" : "class=\"" + tagClass + "\" ";
return "<" + tagName + " id=\"" + containerName + "\" " + classAttr + ">";
}
/**
* Internal action method.<p>
*
* @return SKIP_BODY
* @throws JspException in case something goes wrong
* @see javax.servlet.jsp.tagext.Tag#doStartTag()
*/
@Override
public int doStartTag() throws JspException {
ServletRequest req = pageContext.getRequest();
// This will always be true if the page is called through OpenCms
if (CmsFlexController.isCmsRequest(req)) {
try {
CmsFlexController controller = CmsFlexController.getController(req);
CmsObject cms = controller.getCmsObject();
String requestUri = cms.getRequestContext().getUri();
Locale locale = cms.getRequestContext().getLocale();
CmsJspStandardContextBean standardContext = CmsJspStandardContextBean.getInstance(req);
CmsContainerPageBean containerPage = standardContext.getPage();
if (containerPage == null) {
// get the container page itself, checking the history first
CmsResource pageResource = (CmsResource)CmsHistoryResourceHandler.getHistoryResource(req);
if (pageResource == null) {
pageResource = cms.readResource(requestUri);
}
CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(cms, pageResource, req);
containerPage = xmlContainerPage.getContainerPage(cms, locale);
standardContext.setPage(containerPage);
}
// create tag for container if necessary
boolean createTag = false;
String tagName = CmsStringUtil.isEmptyOrWhitespaceOnly(getTag()) ? DEFAULT_TAG_NAME : getTag();
if (!CREATE_NO_TAG.equals(getTag())) {
createTag = true;
pageContext.getOut().print(getTagOpen(tagName, getName(), getTagClass()));
}
// get the maximal number of elements
int maxElements = getMaxElements(requestUri);
// get the container
CmsContainerBean container = null;
if (containerPage != null) {
container = containerPage.getContainers().get(getName());
}
boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
boolean isUsedAsDetailView = false;
CmsResource detailContent = standardContext.getDetailContent();
if (m_detailView && (detailContent != null)) {
isUsedAsDetailView = true;
}
if (container == null) {
if (!isUsedAsDetailView) {
// container not found
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.get().getBundle().key(
Messages.LOG_CONTAINER_NOT_FOUND_3,
requestUri,
locale,
getName()));
}
if (!isOnline) {
// add container data for the editor
try {
pageContext.getOut().print(
getContainerDataTag(
new CmsContainerBean(getName(), getType(), maxElements, null),
getWidth(),
isUsedAsDetailView));
} catch (JSONException e) {
// should never happen
throw new JspException(e);
}
}
// close tag for the empty container
if (createTag) {
pageContext.getOut().print(getTagClose(tagName));
}
} else {
container = new CmsContainerBean(
getName(),
getType(),
maxElements,
Collections.<CmsContainerElementBean> emptyList());
}
}
if (container != null) {
standardContext.setContainer(container);
// validate the type
if (!getType().equals(container.getType())) {
throw new CmsIllegalStateException(Messages.get().container(
Messages.LOG_WRONG_CONTAINER_TYPE_4,
new Object[] {requestUri, locale, getName(), getType()}));
}
// update the cache
container.setMaxElements(maxElements);
container.setWidth(getWidth());
List<CmsContainerElementBean> allElements = new ArrayList<CmsContainerElementBean>();
CmsContainerElementBean detailElement = null;
if (isUsedAsDetailView) {
detailElement = generateDetailViewElement(cms, detailContent);
}
if (detailElement != null) {
allElements.add(detailElement);
} else {
allElements.addAll(container.getElements());
}
if (!isOnline) {
// add container data for the editor
try {
CmsContainerBean cntBean = new CmsContainerBean(
getName(),
getType(),
maxElements,
allElements);
pageContext.getOut().print(getContainerDataTag(cntBean, getWidth(), isUsedAsDetailView));
} catch (JSONException e) {
// should never happen
throw new JspException(e);
}
}
// iterate over elements to render
for (int i = 0; (i < maxElements) && (i < allElements.size()); i++) {
try {
renderContainerElement(cms, standardContext, allElements.get(i), locale);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(e.getLocalizedMessage(), e);
}
}
}
// close tag for container
if (createTag) {
pageContext.getOut().print(getTagClose(tagName));
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled()) {
LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "container"), ex);
}
throw new javax.servlet.jsp.JspException(ex);
}
}
return SKIP_BODY;
}
/**
* Returns the boolean value if this container is target of detail views.<p>
*
* @return <code>true</code> or <code>false</code>
*/
public String getDetailview() {
return String.valueOf(m_detailView);
}
/**
* Returns the maxElements attribute value.<p>
*
* @return the maxElements attribute value
*/
public String getMaxElements() {
return CmsStringUtil.isEmptyOrWhitespaceOnly(m_maxElements) ? DEFAULT_MAX_ELEMENTS : m_maxElements;
}
/**
* Returns the name attribute value.<p>
*
* @return String the name attribute value
*/
public String getName() {
return m_name;
}
/**
* Returns the tag attribute.<p>
*
* @return the tag attribute
*/
public String getTag() {
return m_tag;
}
/**
* Returns the tag class attribute.<p>
*
* @return the tag class attribute
*/
public String getTagClass() {
return m_tagClass;
}
/**
* Returns the type attribute value.<p>
*
* If the container type has not been set, the name is substituted as type.<p>
*
* @return the type attribute value
*/
public String getType() {
return CmsStringUtil.isEmptyOrWhitespaceOnly(m_type) ? getName() : m_type;
}
/**
* Returns the container width as a string.<p>
*
* @return the container width as a string
*/
public String getWidth() {
return m_width;
}
/**
* @see javax.servlet.jsp.tagext.Tag#release()
*/
@Override
public void release() {
super.release();
m_type = null;
m_name = null;
m_maxElements = null;
m_tag = null;
m_tagClass = null;
m_detailView = false;
}
/**
* Sets if the current container is target of detail views.<p>
*
* @param detailView <code>true</code> or <code>false</code>
*/
public void setDetailview(String detailView) {
m_detailView = Boolean.parseBoolean(detailView);
}
/**
* Sets the maxElements attribute value.<p>
*
* @param maxElements the maxElements value to set
*/
public void setMaxElements(String maxElements) {
m_maxElements = maxElements;
}
/**
* Sets the name attribute value.<p>
*
* @param name the name value to set
*/
public void setName(String name) {
m_name = name;
}
/**
* Sets the tag attribute.<p>
*
* @param tag the createTag to set
*/
public void setTag(String tag) {
m_tag = tag;
}
/**
* Sets the tag class attribute.<p>
*
* @param tagClass the tag class attribute to set
*/
public void setTagClass(String tagClass) {
m_tagClass = tagClass;
}
/**
* Sets the type attribute value.<p>
*
* @param type the type value to set
*/
public void setType(String type) {
m_type = type;
}
/**
* Sets the container width as a string.<p>
*
* @param width the container width as a string
*/
public void setWidth(String width) {
m_width = width;
}
/**
* Returns the closing wrapper tag for a container element.<p>
*
* @param isGroupcontainer <code>true</code> if element is a group-container
*
* @return the closing tag
*
* @see org.opencms.jsp.CmsJspTagContainer#getElementWrapperTagStart(CmsObject, CmsContainerElementBean, boolean)
*/
protected String getElementWrapperTagEnd(boolean isGroupcontainer) {
if (isGroupcontainer) {
return "</div>";
}
return "<div class=\"" + CLASS_CONTAINER_ELEMENT_END_MARKER + "\" style=\"display:none\"></div>";
}
/**
* Returns the opening wrapper tag for elements in the offline project. The wrapper tag is needed by the container-page editor
* to identify elements within a container.<p>
*
* @param cms the cms object
* @param elementBean the element
* @param isGroupcontainer <code>true</code> if element is a group-container
*
* @return the opening tag
*
* @throws CmsException if something goes wrong reading permissions and lock state
*/
protected String getElementWrapperTagStart(
CmsObject cms,
CmsContainerElementBean elementBean,
boolean isGroupcontainer) throws CmsException {
StringBuffer result = new StringBuffer("<div class='");
if (isGroupcontainer) {
result.append(CLASS_GROUP_CONTAINER_ELEMENT_MARKER);
} else {
result.append(CLASS_CONTAINER_ELEMENT_START_MARKER);
}
result.append("'");
Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
String noEditReason = "";
// reinitializing resource to avoid caching issues
elementBean.initResource(cms);
if (CmsResourceTypeXmlContent.isXmlContent(elementBean.getResource())) {
noEditReason = new CmsResourceUtil(cms, elementBean.getResource()).getNoEditReason(wpLocale, true);
} else {
noEditReason = Messages.get().getBundle().key(Messages.GUI_ELEMENT_RESOURCE_CAN_NOT_BE_EDITED_0);
}
result.append(" clientId='").append(elementBean.editorHash()).append("'");
result.append(" alt='").append(elementBean.getSitePath()).append("'");
String typeName = OpenCms.getResourceManager().getResourceType(elementBean.getResource().getTypeId()).getTypeName();
if (elementBean.isCreateNew()) {
result.append(" newType='").append(typeName).append("'");
CmsResourceTypeConfig typeConfig = OpenCms.getADEManager().lookupConfiguration(
cms,
cms.getRequestContext().getRootUri()).getResourceType(typeName);
if (CmsStringUtil.isEmptyOrWhitespaceOnly(noEditReason)
&& ((typeConfig == null) || !typeConfig.checkCreatable(cms))) {
String niceName = CmsWorkplaceMessages.getResourceTypeName(wpLocale, typeName);
noEditReason = Messages.get().getBundle().key(Messages.GUI_CONTAINERPAGE_TYPE_NOT_CREATABLE_1, niceName);
}
}
result.append(" hasprops='").append(hasProperties(cms, elementBean.getResource())).append("'");
CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName);
boolean viewPermission = cms.hasPermissions(
elementBean.getResource(),
CmsPermissionSet.ACCESS_VIEW,
false,
CmsResourceFilter.IGNORE_EXPIRATION)
&& settings.getAccess().getPermissions(cms, elementBean.getResource()).requiresViewPermission();
result.append(" hasviewpermission='").append(viewPermission).append("'");
result.append(" releasedandnotexpired='").append(elementBean.isReleasedAndNotExpired()).append("'");
result.append(" rel='").append(CmsStringUtil.escapeHtml(noEditReason));
if (isGroupcontainer) {
result.append("'>");
} else {
result.append("' style='display:none;'></div>");
}
return result.toString();
}
/**
* Prints the closing tag for an element wrapper if in online mode.<p>
*
* @param isOnline if true, we are online
* @param isGroupcontainer <code>true</code> if element is a group-container
*
* @throws IOException if the output fails
*/
protected void printElementWrapperTagEnd(boolean isOnline, boolean isGroupcontainer) throws IOException {
if (!isOnline) {
pageContext.getOut().print(getElementWrapperTagEnd(isGroupcontainer));
}
}
/**
* Prints the opening element wrapper tag for the container page editor if we are in Offline mode.<p>
*
* @param isOnline true if we are in Online mode
* @param cms the Cms context
* @param elementBean the element bean
* @param isGroupContainer true if the element is a group-container
*
* @throws IOException if the IO fails
* @throws CmsException if something goes wrong
*/
protected void printElementWrapperTagStart(
boolean isOnline,
CmsObject cms,
CmsContainerElementBean elementBean,
boolean isGroupContainer) throws IOException, CmsException {
if (!isOnline) {
pageContext.getOut().print(getElementWrapperTagStart(cms, elementBean, isGroupContainer));
}
}
/**
* Adds a detail view element to a list of elements if necessary.<p>
*
* @param cms the CMS context
* @param allElems the list to which the element should be added
*/
private CmsContainerElementBean generateDetailViewElement(CmsObject cms, CmsResource detailContent) {
CmsContainerElementBean element = null;
if (detailContent != null) {
// get the right formatter
CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
cms,
cms.getRequestContext().getRootUri());
CmsFormatterConfiguration formatters = config.getFormatters(cms, detailContent);
CmsFormatterBean formatter = formatters.getFormatter(getType(), getContainerWidth());
if (formatter != null) {
// create element bean
element = new CmsContainerElementBean(
detailContent.getStructureId(),
formatter.getJspStructureId(),
null,
false); // when used as template element there are no properties
}
}
return element;
}
/**
* Gets the container width as a number.<p>
*
* If the container width is not set, or not a number, -1 will be returned.<p>
*
* @return the container width or -1
*/
private int getContainerWidth() {
int containerWidth = -1;
try {
containerWidth = Integer.parseInt(m_width);
} catch (NumberFormatException e) {
// do nothing, set width to -1
}
return containerWidth;
}
/**
* Parses the maximum element number from the current container and returns the resulting number.<p>
*
* @param requestUri the requested URI
*
* @return the maximum number of elements of the container
*/
private int getMaxElements(String requestUri) {
String containerName = getName();
String containerMaxElements = getMaxElements();
int maxElements = -1;
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(containerMaxElements)) {
try {
maxElements = Integer.parseInt(containerMaxElements);
} catch (NumberFormatException e) {
throw new CmsIllegalStateException(Messages.get().container(
Messages.LOG_WRONG_CONTAINER_MAXELEMENTS_3,
new Object[] {requestUri, containerName, containerMaxElements}), e);
}
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(Messages.get().getBundle().key(
Messages.LOG_MAXELEMENTS_NOT_SET_2,
new Object[] {containerName, requestUri}));
}
}
return maxElements;
}
/**
* Returns the ADE session cache for container elements.<p>
*
* @param cms the cms context
*
* @return the session cache
*/
private CmsADESessionCache getSessionCache(CmsObject cms) {
CmsADESessionCache sessionCache = (CmsADESessionCache)((HttpServletRequest)pageContext.getRequest()).getSession().getAttribute(
CmsADESessionCache.SESSION_ATTR_ADE_CACHE);
if (sessionCache == null) {
sessionCache = new CmsADESessionCache(cms);
((HttpServletRequest)pageContext.getRequest()).getSession().setAttribute(
CmsADESessionCache.SESSION_ATTR_ADE_CACHE,
sessionCache);
}
return sessionCache;
}
/**
* Helper method for checking whether there are properties defined for a given content element.<p>
*
* @param cms the CmsObject to use for VFS operations
* @param resource the resource for which it should be checked whether it has properties
*
* @return true if the resource has properties defined
*
* @throws CmsException if something goes wrong
*/
private boolean hasProperties(CmsObject cms, CmsResource resource) throws CmsException {
if (!CmsResourceTypeXmlContent.isXmlContent(resource)) {
return false;
}
Map<String, CmsXmlContentProperty> propConfig = CmsXmlContentDefinition.getContentHandlerForResource(
cms,
resource).getSettings(cms, resource);
return !propConfig.isEmpty();
}
/**
* Prints an element error tag to the response out.<p>
*
* @param isOnline true if we are in Online mode
* @param elementSitePath the element site path
* @param formatterSitePath the formatter site path
* @param exception the exception causing the error
*
* @throws IOException if something goes wrong writing to response out
*/
private void printElementErrorTag(
boolean isOnline,
String elementSitePath,
String formatterSitePath,
Exception exception) throws IOException {
if (!isOnline) {
String stacktrace = CmsException.getStackTraceAsString(exception);
if (CmsStringUtil.isEmptyOrWhitespaceOnly(stacktrace)) {
stacktrace = null;
} else {
// stacktrace = CmsStringUtil.escapeJavaScript(stacktrace);
stacktrace = CmsEncoder.escapeXml(stacktrace);
}
StringBuffer errorBox = new StringBuffer(256);
errorBox.append("<div style=\"display:block; padding: 5px; border: red solid 2px; color: black; background: white;\" class=\"");
errorBox.append(CLASS_ELEMENT_ERROR);
errorBox.append("\">");
errorBox.append(Messages.get().getBundle().key(
Messages.ERR_CONTAINER_PAGE_ELEMENT_RENDER_ERROR_2,
elementSitePath,
formatterSitePath));
errorBox.append("<br />");
errorBox.append(exception.getLocalizedMessage());
if (stacktrace != null) {
errorBox.append("<span onclick=\"__openStacktraceDialog(event);\" style=\"border: 1px solid black; cursor: pointer;\">");
errorBox.append(Messages.get().getBundle().key(Messages.GUI_LABEL_STACKTRACE_0));
errorBox.append("<span title=\"");
errorBox.append(Messages.get().getBundle().key(Messages.GUI_LABEL_STACKTRACE_0));
errorBox.append("\" class=\"hiddenStacktrace\" style=\"display:none;\"><pre><b>");
errorBox.append(exception.getLocalizedMessage());
errorBox.append("</b>\n\n");
errorBox.append(stacktrace);
errorBox.append("</pre></span></span>");
}
errorBox.append("</div>");
pageContext.getOut().print(errorBox.toString());
}
}
/**
* Renders a container element.<p>
*
* @param cms the CMS context
* @param element the container element to render
* @throws CmsException if something goes wrong reading the resources
* @throws IOException if something goes wrong writing to the response
*/
private void renderContainerElement(
CmsObject cms,
CmsJspStandardContextBean standardContext,
CmsContainerElementBean element,
Locale locale) throws CmsException, CmsXmlException, CmsLoaderException, IOException {
ServletRequest req = pageContext.getRequest();
ServletResponse res = pageContext.getResponse();
String containerType = getType();
int containerWidth = getContainerWidth();
boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
element.initResource(cms);
// writing elements to the session cache to improve performance of the container-page editor
getSessionCache(cms).setCacheContainerElement(element.editorHash(), element);
CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
cms,
cms.getRequestContext().getRootUri());
if (element.isGroupContainer(cms)) {
CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(
cms,
element.getResource(),
req);
CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(
cms,
cms.getRequestContext().getLocale());
if (!groupContainer.getTypes().contains(containerType)) {
//TODO: change message
throw new CmsIllegalStateException(Messages.get().container(
Messages.ERR_XSD_NO_TEMPLATE_FORMATTER_3,
element.getResource().getRootPath(),
OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName(),
containerType));
}
// wrapping the elements with DIV containing initial element data. To be removed by the container-page editor
printElementWrapperTagStart(isOnline, cms, element, true);
for (CmsContainerElementBean subelement : groupContainer.getElements()) {
try {
subelement.initResource(cms);
// writing elements to the session cache to improve performance of the container-page editor
getSessionCache(cms).setCacheContainerElement(subelement.editorHash(), subelement);
CmsFormatterConfiguration subelementFormatters = adeConfig.getFormatters(
cms,
subelement.getResource());
CmsFormatterBean subelementFormatter = subelementFormatters.getFormatter(
containerType,
containerWidth);
if (subelementFormatter == null) {
if (LOG.isErrorEnabled()) {
LOG.error(new CmsIllegalStateException(Messages.get().container(
Messages.ERR_XSD_NO_TEMPLATE_FORMATTER_3,
subelement.getSitePath(),
OpenCms.getResourceManager().getResourceType(subelement.getResource()).getTypeName(),
containerType)));
}
// skip this element, it has no formatter for this container type defined
continue;
}
// execute the formatter JSP for the given element URI
// wrapping the elements with DIV containing initial element data. To be removed by the container-page editor
printElementWrapperTagStart(isOnline, cms, subelement, false);
standardContext.setElement(subelement);
try {
CmsJspTagInclude.includeTagAction(
pageContext,
subelementFormatter.getJspRootPath(),
null,
locale,
false,
isOnline,
null,
CmsRequestUtil.getAtrributeMap(req),
req,
res);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(Messages.get().getBundle().key(
Messages.ERR_CONTAINER_PAGE_ELEMENT_RENDER_ERROR_2,
subelement.getSitePath(),
subelementFormatter), e);
}
printElementErrorTag(
isOnline,
subelement.getSitePath(),
subelementFormatter.getJspRootPath(),
e);
}
printElementWrapperTagEnd(isOnline, false);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(e);
}
}
}
printElementWrapperTagEnd(isOnline, true);
} else {
String formatter = null;
try {
formatter = cms.getSitePath(cms.readResource(element.getFormatterId()));
} catch (CmsException e) {
// the formatter resource can not be found, try reading it form the configuration
CmsFormatterConfiguration elementFormatters = adeConfig.getFormatters(cms, element.getResource());
CmsFormatterBean elementFormatterBean = elementFormatters.getFormatter(containerType, containerWidth);
if (elementFormatterBean == null) {
if (LOG.isErrorEnabled()) {
LOG.error(new CmsIllegalStateException(Messages.get().container(
Messages.ERR_XSD_NO_TEMPLATE_FORMATTER_3,
element.getSitePath(),
OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName(),
containerType)));
}
// skip this element, it has no formatter for this container type defined
return;
}
formatter = elementFormatterBean.getJspRootPath();
}
printElementWrapperTagStart(isOnline, cms, element, false);
standardContext.setElement(element);
try {
// execute the formatter jsp for the given element uri
CmsJspTagInclude.includeTagAction(
pageContext,
formatter,
null,
locale,
false,
isOnline,
null,
CmsRequestUtil.getAtrributeMap(req),
req,
res);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(Messages.get().getBundle().key(
Messages.ERR_CONTAINER_PAGE_ELEMENT_RENDER_ERROR_2,
element.getSitePath(),
formatter), e);
}
printElementErrorTag(isOnline, element.getSitePath(), formatter, e);
}
printElementWrapperTagEnd(isOnline, false);
}
}
}