/* * 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.xml.containerpage; import org.opencms.ade.configuration.CmsADEManager; import org.opencms.file.CmsFile; import org.opencms.file.CmsObject; import org.opencms.file.CmsResource; import org.opencms.file.CmsResourceFilter; import org.opencms.file.types.CmsResourceTypeXmlContainerPage; import org.opencms.file.types.CmsResourceTypeXmlContent; import org.opencms.file.types.I_CmsResourceType; import org.opencms.main.CmsException; import org.opencms.main.OpenCms; import org.opencms.util.CmsUUID; import org.opencms.xml.CmsXmlContentDefinition; import org.opencms.xml.content.CmsXmlContent; import org.opencms.xml.content.CmsXmlContentFactory; import org.opencms.xml.content.CmsXmlContentPropertyHelper; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; /** * One element of a container in a container page.<p> * * @since 8.0 */ public class CmsContainerElementBean { /** Flag indicating if a new element should be created replacing the given one on first edit of a container-page. */ private final boolean m_createNew; /** The client ADE editor hash. */ private transient String m_editorHash; /** The element's structure id. */ private final CmsUUID m_elementId; /** The formatter's structure id. */ private final CmsUUID m_formatterId; /** The configured properties. */ private final Map<String, String> m_individualSettings; /** Indicates whether the represented resource is in memory only and not in the VFS. */ private boolean m_inMemoryOnly; /** The resource of this element. */ private transient CmsResource m_resource; /** The settings of this element containing also default values. */ private transient Map<String, String> m_settings; /** The element site path, only set while rendering. */ private String m_sitePath; /** Indicating if the element resource is released and not expired. */ private boolean m_releasedAndNotExpired; /** * Creates a new container page element bean.<p> * * @param elementId the element's structure id * @param formatterId the formatter's structure id, could be <code>null</code> * @param individualSettings the element settings as a map of name/value pairs * @param createNew <code>true</code> if a new element should be created replacing the given one on first edit of a container-page **/ public CmsContainerElementBean( CmsUUID elementId, CmsUUID formatterId, Map<String, String> individualSettings, boolean createNew) { m_elementId = elementId; m_formatterId = formatterId; Map<String, String> newSettings = (individualSettings == null ? new HashMap<String, String>() : individualSettings); m_individualSettings = Collections.unmodifiableMap(newSettings); String clientId = m_elementId.toString(); if (!m_individualSettings.isEmpty()) { int hash = m_individualSettings.toString().hashCode(); clientId += CmsADEManager.CLIENT_ID_SEPERATOR + hash; } m_editorHash = clientId; m_createNew = createNew; } /** * Clones the given element bean with a different set of settings.<p> * * @param source the element to clone * @param settings the new settings * * @return the element bean */ public static CmsContainerElementBean cloneWithSettings(CmsContainerElementBean source, Map<String, String> settings) { CmsContainerElementBean result = new CmsContainerElementBean( source.m_elementId, source.m_formatterId, settings, source.m_createNew); result.m_resource = source.m_resource; result.m_sitePath = source.m_sitePath; result.m_inMemoryOnly = source.m_inMemoryOnly; if (result.m_inMemoryOnly) { String editorHash = source.m_editorHash; if (editorHash.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) { editorHash = editorHash.substring(0, editorHash.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR)); } editorHash += result.getSettingsHash(); result.m_editorHash = editorHash; } return result; } /** * Creates an element bean for the given resource type.<p> * <b>The represented resource will be in memory only and not in the VFS!!!.</b><p> * * @param cms the CMS context * @param resourceType the resource type * @param targetFolder the parent folder of the resource * @param individualSettings the element settings as a map of name/value pairs * @param locale the locale to use * * @return the created element bean * @throws CmsException * @throws IllegalArgumentException if the resource type not instance of {@link org.opencms.file.types.CmsResourceTypeXmlContent} */ public static CmsContainerElementBean createElementForResourceType( CmsObject cms, I_CmsResourceType resourceType, String targetFolder, Map<String, String> individualSettings, Locale locale) throws CmsException { if (!(resourceType instanceof CmsResourceTypeXmlContent)) { throw new IllegalArgumentException(); } CmsContainerElementBean elementBean = new CmsContainerElementBean( CmsUUID.getNullUUID(), null, individualSettings, true); elementBean.m_inMemoryOnly = true; elementBean.m_editorHash = resourceType.getTypeName() + elementBean.getSettingsHash(); byte[] content = new byte[0]; String schema = ((CmsResourceTypeXmlContent)resourceType).getSchema(); if (schema != null) { // must set URI of OpenCms user context to parent folder of created resource, // in order to allow reading of properties for default values CmsObject newCms = OpenCms.initCmsObject(cms); newCms.getRequestContext().setUri(targetFolder); // unmarshal the content definition for the new resource CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); CmsXmlContent xmlContent = CmsXmlContentFactory.createDocument( newCms, locale, OpenCms.getSystemInfo().getDefaultEncoding(), contentDefinition); // adding all other available locales for (Locale otherLocale : OpenCms.getLocaleManager().getAvailableLocales()) { if (!locale.equals(otherLocale)) { xmlContent.addLocale(newCms, otherLocale); } } content = xmlContent.marshal(); } elementBean.m_resource = new CmsFile( CmsUUID.getNullUUID(), CmsUUID.getNullUUID(), targetFolder + "~", resourceType.getTypeId(), 0, cms.getRequestContext().getCurrentProject().getUuid(), CmsResource.STATE_NEW, 0, cms.getRequestContext().getCurrentUser().getId(), 0, cms.getRequestContext().getCurrentUser().getId(), CmsResource.DATE_RELEASED_DEFAULT, CmsResource.DATE_EXPIRED_DEFAULT, 1, content.length, 0, 0, content); return elementBean; } /** * Returns the ADE client editor has value.<p> * * @return the ADE client editor has value */ public String editorHash() { return m_editorHash; } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (!(obj instanceof CmsContainerElementBean)) { return false; } return editorHash().equals(((CmsContainerElementBean)obj).editorHash()); } /** * Returns the structure id of the formatter of this element.<p> * * @return the structure id of the formatter of this element */ public CmsUUID getFormatterId() { return m_formatterId; } /** * Returns the structure id of the resource of this element.<p> * * @return the structure id of the resource of this element */ public CmsUUID getId() { return m_elementId; } /** * Returns the settings of this element.<p> * * @return the settings of this element */ public Map<String, String> getIndividualSettings() { return m_individualSettings; } /** * Returns the resource of this element.<p> * * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p> * * @return the resource of this element * * @see #initResource(CmsObject) */ public CmsResource getResource() { return m_resource; } /** * Returns the element settings including default values for settings not set.<p> * Will return <code>null</code> if the element bean has not been initialized with {@link #initResource(org.opencms.file.CmsObject)}.<p> * * @return the element settings */ public Map<String, String> getSettings() { return m_settings; } /** * Returns the site path of the resource of this element.<p> * * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p> * * @return the site path of the resource of this element * * @see #initResource(CmsObject) */ public String getSitePath() { return m_sitePath; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return m_editorHash.hashCode(); } /** * Initializes the resource and the site path of this element.<p> * * @param cms the CMS context * * @throws CmsException if something goes wrong reading the element resource */ public void initResource(CmsObject cms) throws CmsException { if (m_resource == null) { if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { m_resource = cms.readResource(getId()); m_releasedAndNotExpired = true; } else { m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION); m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime()); } } else if (!isInMemoryOnly()) { CmsUUID id = m_resource.getStructureId(); if (id == null) { id = getId(); } // the resource object may have a wrong root path, e.g. if it was created before the resource was moved if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { m_resource = cms.readResource(getId()); m_releasedAndNotExpired = true; } else { m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION); m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime()); } } if (m_settings == null) { m_settings = CmsXmlContentPropertyHelper.mergeDefaults(cms, m_resource, m_individualSettings); } // redo on every init call to ensure sitepath is calculated for current site m_sitePath = cms.getSitePath(m_resource); } /** * Returns if a new element should be created replacing the given one on first edit of a container-page.<p> * * @return <code>true</code> if a new element should be created replacing the given one on first edit of a container-page */ public boolean isCreateNew() { return m_createNew; } /** * Tests whether this element refers to a group container.<p> * * @param cms the CmsObject used for VFS operations * * @return true if the container element refers to a group container * * @throws CmsException if something goes wrong */ public boolean isGroupContainer(CmsObject cms) throws CmsException { if (m_resource == null) { initResource(cms); } return CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME.equals(OpenCms.getResourceManager().getResourceType( m_resource).getTypeName()); } /** * Returns if the represented resource is in memory only and not persisted in the VFS.<p> * * @return <code>true</code> if the represented resource is in memory only and not persisted in the VFS */ public boolean isInMemoryOnly() { return m_inMemoryOnly; } /** * Returns if the element resource is released and not expired.<p> * * @return <code>true</code> if the element resource is released and not expired */ public boolean isReleasedAndNotExpired() { return isInMemoryOnly() || m_releasedAndNotExpired; } /** * @see java.lang.Object#toString() */ @Override public String toString() { return editorHash(); } /** * Gets the hash code for the element settings.<p> * * @return the hash code for the element settings */ private String getSettingsHash() { if (!m_individualSettings.isEmpty()) { int hash = m_individualSettings.toString().hashCode(); return CmsADEManager.CLIENT_ID_SEPERATOR + hash; } return ""; } }