
org.opencms.ade.containerpage.CmsModelGroupHelper Maven / Gradle / Ivy
Show all versions of opencms-test Show documentation
/*
* 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.ade.containerpage;
import org.opencms.ade.configuration.CmsADEConfigData;
import org.opencms.ade.configuration.CmsResourceTypeConfig;
import org.opencms.ade.containerpage.shared.CmsContainerElement;
import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsUser;
import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
import org.opencms.lock.CmsLock;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
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.CmsXmlContainerPage;
import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
/**
* Handles all model group specific tasks.
*/
public class CmsModelGroupHelper {
/** The name of the container storing the groups base element. */
public static final String MODEL_GROUP_BASE_CONTAINER = "base_container";
/** Static reference to the log. */
private static final Log LOG = CmsLog.getLog(CmsModelGroupHelper.class);
/** The current cms context. */
private CmsObject m_cms;
/** The session cache instance. */
private CmsADESessionCache m_sessionCache;
/** The configuration data of the current container page location. */
private CmsADEConfigData m_configData;
/** Indicating the edit model groups mode. */
private boolean m_isEditingModelGroups;
/**
* Constructor.
*
* @param cms the current cms context
* @param configData the configuration data
* @param sessionCache the session cache
* @param isEditingModelGroups the edit model groups flag
*/
public CmsModelGroupHelper(
CmsObject cms,
CmsADEConfigData configData,
CmsADESessionCache sessionCache,
boolean isEditingModelGroups) {
m_cms = cms;
m_sessionCache = sessionCache;
m_configData = configData;
m_isEditingModelGroups = isEditingModelGroups;
}
/**
* Creates a new model group resource.
*
* @param cms the current cms context
* @param configData the configuration data
*
* @return the new resource
*
* @throws CmsException in case creating the resource fails
*/
public static CmsResource createModelGroup(CmsObject cms, CmsADEConfigData configData) throws CmsException {
CmsResourceTypeConfig typeConfig = configData.getResourceType(
CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME);
return typeConfig.createNewElement(cms, configData.getBasePath());
}
/**
* Returns if the given resource is a model group resource.
*
* @param resource the resource
*
* @return true
if the given resource is a model group resource
*/
public static boolean isModelGroupResource(CmsResource resource) {
return CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME.equals(
OpenCms.getResourceManager().getResourceType(resource).getTypeName());
}
/**
* Adds the model group elements to the page.
*
* @param elements the requested elements
* @param page the page
* @param locale the content locale
*
* @return the adjusted page
*
* @throws CmsException in case something goes wrong
*/
public CmsContainerPageBean prepareforModelGroupContent(
Map elements,
CmsContainerPageBean page,
Locale locale) throws CmsException {
for (Entry entry : elements.entrySet()) {
CmsContainerElementBean element = entry.getValue();
CmsContainerPageBean modelPage = null;
String modelInstanceId = null;
boolean foundInstance = false;
if (CmsModelGroupHelper.isModelGroupResource(element.getResource())) {
modelPage = getContainerPageBean(element.getResource());
CmsContainerElementBean baseElement = getModelBaseElement(modelPage);
if (baseElement == null) {
break;
}
String baseInstanceId = baseElement.getInstanceId();
String originalInstanceId = element.getInstanceId();
element = getModelReplacementElement(element, baseElement, true);
List modelContainers = readModelContainers(
baseInstanceId,
originalInstanceId,
modelPage);
if (!m_isEditingModelGroups && baseElement.isCopyModel()) {
modelContainers = createNewElementsForModelGroup(m_cms, modelContainers, locale);
}
modelContainers.addAll(page.getContainers().values());
page = new CmsContainerPageBean(modelContainers);
// update the entry element value, as the settings will have changed
entry.setValue(element);
// also update the session cache
m_sessionCache.setCacheContainerElement(element.editorHash(), element);
} else {
// here we need to make sure to remove the source container page setting and to set a new element instance id
Map settings = new HashMap(element.getIndividualSettings());
String source = settings.get(CmsContainerpageService.SOURCE_CONTAINERPAGE_ID_SETTING);
settings.remove(CmsContainerpageService.SOURCE_CONTAINERPAGE_ID_SETTING);
if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(source)) {
try {
CmsUUID sourceId = new CmsUUID(source);
CmsResource sourcePage = m_cms.readResource(sourceId);
if (CmsResourceTypeXmlContainerPage.isContainerPage(sourcePage)) {
CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(
m_cms,
m_cms.readFile(sourcePage));
modelPage = xmlCnt.getContainerPage(m_cms);
modelInstanceId = element.getInstanceId();
}
settings.remove(CmsContainerElement.ELEMENT_INSTANCE_ID);
element = CmsContainerElementBean.cloneWithSettings(element, settings);
if (modelPage != null) {
Map> containerByParent = new HashMap>();
for (CmsContainerBean container : modelPage.getContainers().values()) {
if (container.getParentInstanceId() != null) {
if (!containerByParent.containsKey(container.getParentInstanceId())) {
containerByParent.put(
container.getParentInstanceId(),
new ArrayList());
}
containerByParent.get(container.getParentInstanceId()).add(container);
}
if (!foundInstance) {
for (CmsContainerElementBean child : container.getElements()) {
if (modelInstanceId == null) {
if (child.getId().equals(element.getId())) {
modelInstanceId = child.getInstanceId();
foundInstance = true;
// we also want to keep the settings of the model group
Map setting = new HashMap(
child.getIndividualSettings());
setting.remove(CmsContainerElement.ELEMENT_INSTANCE_ID);
element = CmsContainerElementBean.cloneWithSettings(element, setting);
break;
}
} else {
if (modelInstanceId.equals(child.getInstanceId())) {
foundInstance = true;
break;
}
}
}
}
}
if (foundInstance && containerByParent.containsKey(modelInstanceId)) {
List modelContainers = collectModelStructure(
modelInstanceId,
element.getInstanceId(),
containerByParent);
modelContainers = createNewElementsForModelGroup(m_cms, modelContainers, locale);
modelContainers.addAll(page.getContainers().values());
page = new CmsContainerPageBean(modelContainers);
}
}
// update the entry element value, as the settings will have changed
entry.setValue(element);
// also update the session cache
m_sessionCache.setCacheContainerElement(element.editorHash(), element);
} catch (Exception e) {
LOG.info(e.getLocalizedMessage(), e);
}
}
}
}
return page;
}
/**
* Reads the present model groups and merges their containers into the page.
*
* @param page the container page
*
* @return the resulting container page
*/
public CmsContainerPageBean readModelGroups(CmsContainerPageBean page) {
List resultContainers = new ArrayList();
for (CmsContainerBean container : page.getContainers().values()) {
boolean hasModels = false;
List elements = new ArrayList();
for (CmsContainerElementBean element : container.getElements()) {
try {
element.initResource(m_cms);
if (isModelGroupResource(element.getResource())) {
hasModels = true;
CmsContainerPageBean modelGroupPage = getContainerPageBean(element.getResource());
CmsContainerElementBean baseElement = getModelBaseElement(modelGroupPage);
if (baseElement == null) {
break;
}
String baseInstanceId = baseElement.getInstanceId();
CmsContainerElementBean replaceElement = getModelReplacementElement(
element,
baseElement,
false);
m_sessionCache.setCacheContainerElement(replaceElement.editorHash(), replaceElement);
elements.add(replaceElement);
resultContainers.addAll(
readModelContainers(baseInstanceId, element.getInstanceId(), modelGroupPage));
} else {
elements.add(element);
}
} catch (CmsException e) {
LOG.info(e.getLocalizedMessage(), e);
}
}
if (hasModels) {
resultContainers.add(
new CmsContainerBean(
container.getName(),
container.getType(),
container.getParentInstanceId(),
container.getMaxElements(),
elements));
} else {
resultContainers.add(container);
}
}
return new CmsContainerPageBean(resultContainers);
}
/**
* Removes the model group containers.
*
* @param page the container page state
*
* @return the container page without the model group containers
*/
public CmsContainerPageBean removeModelGroupContainers(CmsContainerPageBean page) {
Map> containersByParent = getContainerByParent(page);
Set modelInstances = new HashSet();
for (CmsContainerElementBean element : page.getElements()) {
if (element.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID)) {
modelInstances.add(element.getInstanceId());
}
}
Set descendingInstances = new HashSet();
for (String modelInstance : modelInstances) {
descendingInstances.addAll(collectDescendingInstances(modelInstance, containersByParent));
}
List containers = new ArrayList();
for (CmsContainerBean container : page.getContainers().values()) {
if ((container.getParentInstanceId() == null)
|| !descendingInstances.contains(container.getParentInstanceId())) {
// iterate the container elements to replace the model group elements
List elements = new ArrayList();
for (CmsContainerElementBean element : container.getElements()) {
if (modelInstances.contains(element.getInstanceId())) {
CmsUUID modelId = new CmsUUID(
element.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID));
CmsContainerElementBean replacer = new CmsContainerElementBean(
modelId,
element.getFormatterId(),
element.getIndividualSettings(),
false);
elements.add(replacer);
} else {
elements.add(element);
}
}
containers.add(
new CmsContainerBean(
container.getName(),
container.getType(),
container.getParentInstanceId(),
container.getMaxElements(),
elements));
}
}
return new CmsContainerPageBean(containers);
}
/**
* Saves the model groups of the given container page.
*
* @param page the container page
*
* @return the container page referencing the saved model groups
*/
public CmsContainerPageBean saveModelGroups(CmsContainerPageBean page) {
Map> containersByParent = getContainerByParent(page);
Map modelInstances = new HashMap();
Set descendingInstances = new HashSet();
for (CmsContainerElementBean element : page.getElements()) {
String modelGroupId = null;
if (element.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID)
|| element.isModelGroup()) {
modelGroupId = element.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID);
modelInstances.put(element.getInstanceId(), modelGroupId);
Set childInstances = collectDescendingInstances(element.getInstanceId(), containersByParent);
descendingInstances.addAll(childInstances);
CmsResource modelGroup = null;
try {
modelGroup = m_cms.readResource(new CmsUUID(modelGroupId));
ensureLock(modelGroup);
String title = element.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_TITLE);
String description = element.getIndividualSettings().get(
CmsContainerElement.MODEL_GROUP_DESCRIPTION);
String groupType = "";
if (Boolean.valueOf(
element.getIndividualSettings().get(CmsContainerElement.USE_AS_COPY_MODEL)).booleanValue()) {
groupType = CmsContainerElement.USE_AS_COPY_MODEL;
}
List props = new ArrayList();
props.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, title));
props.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_DESCRIPTION, description, description));
props.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS, groupType, groupType));
m_cms.writePropertyObjects(modelGroup, props);
List modelContainers = new ArrayList();
CmsContainerElementBean baseElement = element.clone();
CmsContainerBean baseContainer = new CmsContainerBean(
MODEL_GROUP_BASE_CONTAINER,
MODEL_GROUP_BASE_CONTAINER,
null,
Collections.singletonList(baseElement));
modelContainers.add(baseContainer);
for (String childInstance : childInstances) {
if (containersByParent.containsKey(childInstance)) {
modelContainers.addAll(containersByParent.get(childInstance));
}
}
CmsContainerPageBean modelPage = new CmsContainerPageBean(modelContainers);
CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(
m_cms,
m_cms.readFile(modelGroup));
xmlCnt.save(m_cms, modelPage);
tryUnlock(modelGroup);
} catch (CmsException e) {
LOG.error("Error saving model group resource.", e);
}
}
}
List containers = new ArrayList();
for (CmsContainerBean container : page.getContainers().values()) {
if ((container.getParentInstanceId() == null)
|| !descendingInstances.contains(container.getParentInstanceId())) {
// iterate the container elements to replace the model group elements
List elements = new ArrayList();
for (CmsContainerElementBean element : container.getElements()) {
if (modelInstances.containsKey(element.getInstanceId())) {
CmsUUID modelId = new CmsUUID(modelInstances.get(element.getInstanceId()));
CmsContainerElementBean replacer = new CmsContainerElementBean(
modelId,
element.getFormatterId(),
element.getIndividualSettings(),
false);
elements.add(replacer);
} else {
elements.add(element);
}
}
containers.add(
new CmsContainerBean(
container.getName(),
container.getType(),
container.getParentInstanceId(),
container.getMaxElements(),
elements));
}
}
return new CmsContainerPageBean(containers);
}
/**
* Adjusts formatter settings and initializes a new instance id for the given container element.
*
* @param element the container element
* @param originalContainer the original parent container name
* @param adjustedContainer the target container name
*
* @return the new element instance
*/
private CmsContainerElementBean adjustSettings(
CmsContainerElementBean element,
String originalContainer,
String adjustedContainer) {
Map settings = new HashMap(element.getIndividualSettings());
settings.put(CmsContainerElement.ELEMENT_INSTANCE_ID, new CmsUUID().toString());
String formatterId = settings.remove(CmsFormatterConfig.getSettingsKeyForContainer(originalContainer));
settings.put(CmsFormatterConfig.getSettingsKeyForContainer(adjustedContainer), formatterId);
return CmsContainerElementBean.cloneWithSettings(element, settings);
}
/**
* Returns the descending instance id's to the given element instance.
*
* @param instanceId the instance id
* @param containersByParent the container page containers by parent instance id
*
* @return the containers
*/
private Set collectDescendingInstances(
String instanceId,
Map> containersByParent) {
Set descendingInstances = new HashSet();
descendingInstances.add(instanceId);
if (containersByParent.containsKey(instanceId)) {
for (CmsContainerBean container : containersByParent.get(instanceId)) {
for (CmsContainerElementBean element : container.getElements()) {
descendingInstances.addAll(collectDescendingInstances(element.getInstanceId(), containersByParent));
}
}
}
return descendingInstances;
}
/**
* Collects the model group structure.
*
* @param modelInstanceId the model instance id
* @param replaceModelId the local instance id
* @param containerByParent the model group page containers by parent instance id
*
* @return the collected containers
*/
private List collectModelStructure(
String modelInstanceId,
String replaceModelId,
Map> containerByParent) {
List result = new ArrayList();
if (containerByParent.containsKey(modelInstanceId)) {
for (CmsContainerBean container : containerByParent.get(modelInstanceId)) {
String adjustedContainerName = replaceModelId + container.getName().substring(modelInstanceId.length());
List elements = new ArrayList();
for (CmsContainerElementBean element : container.getElements()) {
CmsContainerElementBean copyElement = adjustSettings(
element,
container.getName(),
adjustedContainerName);
m_sessionCache.setCacheContainerElement(copyElement.editorHash(), copyElement);
elements.add(copyElement);
result.addAll(
collectModelStructure(element.getInstanceId(), copyElement.getInstanceId(), containerByParent));
}
result.add(
new CmsContainerBean(
adjustedContainerName,
container.getType(),
replaceModelId,
container.getMaxElements(),
elements));
}
}
return result;
}
/**
* Creates new resources for elements marked with create as new.
*
* @param cms the cms context
* @param modelContainers the model containers
* @param locale the content locale
*
* @return the updated model containers
*
* @throws CmsException in case something goes wrong
*/
private List createNewElementsForModelGroup(
CmsObject cms,
List modelContainers,
Locale locale) throws CmsException {
Map newResources = new HashMap();
CmsObject cloneCms = OpenCms.initCmsObject(cms);
cloneCms.getRequestContext().setLocale(locale);
for (CmsContainerBean container : modelContainers) {
for (CmsContainerElementBean element : container.getElements()) {
if (element.isCreateNew() && !newResources.containsKey(element.getId())) {
element.initResource(cms);
String typeName = OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName();
CmsResourceTypeConfig typeConfig = m_configData.getResourceType(typeName);
if (typeConfig == null) {
throw new IllegalArgumentException(
"Can not copy template model element '"
+ element.getResource().getRootPath()
+ "' because the resource type '"
+ typeName
+ "' is not available in this sitemap.");
}
CmsResource newResource = typeConfig.createNewElement(
cloneCms,
element.getResource(),
m_configData.getBasePath());
newResources.put(element.getId(), newResource);
}
}
}
if (!newResources.isEmpty()) {
List updatedContainers = new ArrayList();
for (CmsContainerBean container : modelContainers) {
List updatedElements = new ArrayList();
for (CmsContainerElementBean element : container.getElements()) {
if (newResources.containsKey(element.getId())) {
CmsContainerElementBean newBean = new CmsContainerElementBean(
newResources.get(element.getId()).getStructureId(),
element.getFormatterId(),
element.getIndividualSettings(),
false);
updatedElements.add(newBean);
} else {
updatedElements.add(element);
}
}
CmsContainerBean updatedContainer = new CmsContainerBean(
container.getName(),
container.getType(),
container.getParentInstanceId(),
container.getMaxElements(),
updatedElements);
updatedContainers.add(updatedContainer);
}
modelContainers = updatedContainers;
}
return modelContainers;
}
/**
* Locks the given resource.
*
* @param resource the resource to lock
*
* @throws CmsException in case locking fails
*/
private void ensureLock(CmsResource resource) throws CmsException {
CmsUser user = m_cms.getRequestContext().getCurrentUser();
CmsLock lock = m_cms.getLock(resource);
if (!lock.isOwnedBy(user)) {
m_cms.lockResourceTemporary(resource);
} else if (!lock.isOwnedInProjectBy(user, m_cms.getRequestContext().getCurrentProject())) {
m_cms.changeLock(resource);
}
}
/**
* Collects the page containers by parent instance id
*
* @param page the page
*
* @return the containers by parent id
*/
private Map> getContainerByParent(CmsContainerPageBean page) {
Map> containerByParent = new HashMap>();
for (CmsContainerBean container : page.getContainers().values()) {
if (container.getParentInstanceId() != null) {
if (!containerByParent.containsKey(container.getParentInstanceId())) {
containerByParent.put(container.getParentInstanceId(), new ArrayList());
}
containerByParent.get(container.getParentInstanceId()).add(container);
}
}
return containerByParent;
}
/**
* Unmarshals the given resource.
*
* @param resource the resource
*
* @return the container page bean
*
* @throws CmsException in case unmarshalling fails
*/
private CmsContainerPageBean getContainerPageBean(CmsResource resource) throws CmsException {
CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(m_cms, m_cms.readFile(resource));
return xmlCnt.getContainerPage(m_cms);
}
/**
* Returns the model group base element.
*
* @param modelGroupPage the model group page
*
* @return the base element
*/
private CmsContainerElementBean getModelBaseElement(CmsContainerPageBean modelGroupPage) {
CmsContainerBean container = modelGroupPage.getContainers().get(MODEL_GROUP_BASE_CONTAINER);
return container != null ? container.getElements().get(0) : null;
}
/**
* Returns the the element to be rendered as the model group base.
*
* @param element the original element
* @param baseElement the model group base
* @param allowCopyModel if copy models are allowed
*
* @return the element
*/
private CmsContainerElementBean getModelReplacementElement(
CmsContainerElementBean element,
CmsContainerElementBean baseElement,
boolean allowCopyModel) {
Map settings = new HashMap(element.getIndividualSettings());
if (m_isEditingModelGroups || !(baseElement.isCopyModel() && allowCopyModel)) {
// skip the model id in case of copy models
settings.put(CmsContainerElement.MODEL_GROUP_ID, element.getId().toString());
try {
CmsProperty titleProp = m_cms.readPropertyObject(
element.getResource(),
CmsPropertyDefinition.PROPERTY_TITLE,
false);
settings.put(CmsContainerElement.MODEL_GROUP_TITLE, titleProp.getValue());
CmsProperty descProp = m_cms.readPropertyObject(
element.getResource(),
CmsPropertyDefinition.PROPERTY_DESCRIPTION,
false);
settings.put(CmsContainerElement.MODEL_GROUP_DESCRIPTION, descProp.getValue());
} catch (CmsException e) {
LOG.error(e.getLocalizedMessage(), e);
}
if (allowCopyModel) {
// transfer all other settings
for (Entry settingEntry : baseElement.getIndividualSettings().entrySet()) {
if (!settings.containsKey(settingEntry.getKey())) {
settings.put(settingEntry.getKey(), settingEntry.getValue());
}
}
}
} else if (baseElement.isCopyModel()) {
settings.put(CmsContainerElement.MODEL_GROUP_STATE, ModelGroupState.wasModelGroup.name());
}
return CmsContainerElementBean.cloneWithSettings(baseElement, settings);
}
/**
* Returns the model containers.
*
* @param modelInstanceId the model instance id
* @param localInstanceId the local instance id
* @param modelPage the model page bean
*
* @return the model group containers
*/
private List readModelContainers(
String modelInstanceId,
String localInstanceId,
CmsContainerPageBean modelPage) {
Map> containerByParent = getContainerByParent(modelPage);
List modelContainers;
if (containerByParent.containsKey(modelInstanceId)) {
modelContainers = collectModelStructure(modelInstanceId, localInstanceId, containerByParent);
} else {
modelContainers = Collections.emptyList();
}
return modelContainers;
}
/**
* Tries to unlock a resource.
*
* @param resource the resource to unlock
*/
private void tryUnlock(CmsResource resource) {
try {
m_cms.unlockResource(resource);
} catch (CmsException e) {
LOG.debug("Unable to unlock " + resource.getRootPath(), e);
}
}
}