org.opencms.i18n.tools.CmsContainerPageCopier 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 & 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, 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.i18n.tools;
import org.opencms.ade.configuration.CmsADEConfigData;
import org.opencms.ade.configuration.CmsResourceTypeConfig;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.i18n.CmsLocaleGroupService;
import org.opencms.i18n.CmsLocaleGroupService.Status;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.loader.I_CmsFileNameGenerator;
import org.opencms.lock.CmsLockActionRecord;
import org.opencms.lock.CmsLockActionRecord.LockChange;
import org.opencms.lock.CmsLockUtil;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.site.CmsSite;
import org.opencms.ui.Messages;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsMacroResolver;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
import org.opencms.xml.CmsXmlException;
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 org.opencms.xml.content.CmsXmlContent;
import org.opencms.xml.content.CmsXmlContentFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
* Helper class for copying container pages including some of their elements.
*/
public class CmsContainerPageCopier {
/**
* Enum representing the element copy mode.
*/
public enum CopyMode {
/** Choose between reuse / copy automatically depending on source / target locale and the configuration .*/
automatic,
/** Do not copy elements. */
reuse,
/** Automatically determine when to copy elements. */
smartCopy,
/** Like smartCopy, but also converts locales of copied elements. */
smartCopyAndChangeLocale;
}
/**
* Exception indicating that no custom replacement element was found
* for a type which requires replacement.
*/
public static class NoCustomReplacementException extends Exception {
/** Serial version id. */
private static final long serialVersionUID = 1L;
/** The resource for which no exception was found. */
private CmsResource m_resource;
/**
* Creates a new instance.
*
* @param resource the resource for which no replacement was found
*/
public NoCustomReplacementException(CmsResource resource) {
super();
m_resource = resource;
}
/**
* Gets the resource for which no replacement was found.
*
* @return the resource
*/
public CmsResource getResource() {
return m_resource;
}
}
/** The log instance used for this class. */
private static final Log LOG = CmsLog.getLog(CmsContainerPageCopier.class);
/** The CMS context used by this object. */
private CmsObject m_cms;
/** The copied resource. */
private CmsResource m_copiedFolderOrPage;
/** The copy mode. */
private CopyMode m_copyMode = CopyMode.smartCopyAndChangeLocale;
/** List of created resources. */
private List m_createdResources = Lists.newArrayList();
/** Map of custom replacements. */
private Map m_customReplacements;
/** Maps structure ids of original container elements to structure ids of their copies/replacements. */
private Map m_elementReplacements = Maps.newHashMap();
/** The original page. */
private CmsResource m_originalPage;
/** The target folder. */
private CmsResource m_targetFolder;
/** Resource types which require custom replacements. */
private Set m_typesWithRequiredReplacements;
/**
* Creates a new instance.
*
* @param cms the CMS context to use
*/
public CmsContainerPageCopier(CmsObject cms) {
m_cms = cms;
}
/**
* Converts locales for the copied container element.
*
* @param elementResource the copied container element
* @throws CmsException if something goes wrong
*/
public void adjustLocalesForElement(CmsResource elementResource) throws CmsException {
if (m_copyMode != CopyMode.smartCopyAndChangeLocale) {
return;
}
CmsFile file = m_cms.readFile(elementResource);
Locale oldLocale = OpenCms.getLocaleManager().getDefaultLocale(m_cms, m_originalPage);
Locale newLocale = OpenCms.getLocaleManager().getDefaultLocale(m_cms, m_targetFolder);
CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, file);
try {
content.moveLocale(oldLocale, newLocale);
LOG.info("Replacing locale " + oldLocale + " -> " + newLocale + " for " + elementResource.getRootPath());
file.setContents(content.marshal());
m_cms.writeFile(file);
} catch (CmsXmlException e) {
LOG.info(
"NOT replacing locale for "
+ elementResource.getRootPath()
+ ": old="
+ oldLocale
+ ", new="
+ newLocale
+ ", contentLocales="
+ content.getLocales());
}
}
/**
* Gets the copied folder or page.
*
* @return the copied folder or page
*/
public CmsResource getCopiedFolderOrPage() {
return m_copiedFolderOrPage;
}
/**
* Returns the target folder.
*
* @return the target folder
*/
public CmsResource getTargetFolder() {
return m_targetFolder;
}
/**
* Produces the replacement for a container page element to use in a copy of an existing container page.
*
* @param targetPage the target container page
* @param originalElement the original element
* @return the replacement element for the copied page
*
* @throws CmsException if something goes wrong
* @throws NoCustomReplacementException if a custom replacement is not found for a type which requires it
*/
public CmsContainerElementBean replaceContainerElement(
CmsResource targetPage,
CmsContainerElementBean originalElement)
throws CmsException, NoCustomReplacementException {
// if (m_elementReplacements.containsKey(originalElement.getId()
CmsObject targetCms = OpenCms.initCmsObject(m_cms);
CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(m_targetFolder.getRootPath());
if (site != null) {
targetCms.getRequestContext().setSiteRoot(site.getSiteRoot());
}
if ((originalElement.getFormatterId() == null) || (originalElement.getId() == null)) {
String rootPath = m_originalPage != null ? m_originalPage.getRootPath() : "???";
LOG.warn("Skipping container element because of missing id in page: " + rootPath);
return null;
}
if (m_elementReplacements.containsKey(originalElement.getId())) {
return new CmsContainerElementBean(
m_elementReplacements.get(originalElement.getId()),
maybeReplaceFormatter(originalElement.getFormatterId()),
maybeReplaceFormatterInSettings(originalElement.getIndividualSettings()),
originalElement.isCreateNew());
} else {
CmsResource originalResource = m_cms.readResource(
originalElement.getId(),
CmsResourceFilter.IGNORE_EXPIRATION);
I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(originalResource);
CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(m_cms, targetPage.getRootPath());
CmsResourceTypeConfig typeConfig = config.getResourceType(type.getTypeName());
if ((m_copyMode != CopyMode.reuse)
&& (typeConfig != null)
&& (originalElement.isCreateNew() || typeConfig.isCopyInModels())
&& !type.getTypeName().equals(CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME)) {
CmsResource resourceCopy = typeConfig.createNewElement(
targetCms,
originalResource,
targetPage.getRootPath());
CmsContainerElementBean copy = new CmsContainerElementBean(
resourceCopy.getStructureId(),
maybeReplaceFormatter(originalElement.getFormatterId()),
maybeReplaceFormatterInSettings(originalElement.getIndividualSettings()),
originalElement.isCreateNew());
m_elementReplacements.put(originalElement.getId(), resourceCopy.getStructureId());
LOG.info(
"Copied container element " + originalResource.getRootPath() + " -> " + resourceCopy.getRootPath());
CmsLockActionRecord record = null;
try {
record = CmsLockUtil.ensureLock(m_cms, resourceCopy);
adjustLocalesForElement(resourceCopy);
} finally {
if ((record != null) && (record.getChange() == LockChange.locked)) {
m_cms.unlockResource(resourceCopy);
}
}
return copy;
} else if (m_customReplacements != null) {
CmsUUID replacementId = m_customReplacements.get(originalElement.getId());
if (replacementId != null) {
return new CmsContainerElementBean(
replacementId,
maybeReplaceFormatter(originalElement.getFormatterId()),
maybeReplaceFormatterInSettings(originalElement.getIndividualSettings()),
originalElement.isCreateNew());
} else {
if ((m_typesWithRequiredReplacements != null)
&& m_typesWithRequiredReplacements.contains(type.getTypeName())) {
throw new NoCustomReplacementException(originalResource);
} else {
return originalElement;
}
}
} else {
LOG.info("Reusing container element: " + originalResource.getRootPath());
return originalElement;
}
}
}
/**
* Replaces the elements in the copied container page with copies, if appropriate based on the current copy mode.
*
* @param containerPage the container page copy whose elements should be replaced with copies
*
* @throws CmsException if something goes wrong
* @throws NoCustomReplacementException if a custom replacement element was not found for a type which requires it
*/
public void replaceElements(CmsResource containerPage) throws CmsException, NoCustomReplacementException {
CmsObject rootCms = OpenCms.initCmsObject(m_cms);
rootCms.getRequestContext().setSiteRoot("");
CmsObject targetCms = OpenCms.initCmsObject(m_cms);
targetCms.getRequestContext().setSiteRoot("");
CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(m_targetFolder.getRootPath());
if (site != null) {
targetCms.getRequestContext().setSiteRoot(site.getSiteRoot());
} else if (OpenCms.getSiteManager().startsWithShared(m_targetFolder.getRootPath())) {
targetCms.getRequestContext().setSiteRoot(OpenCms.getSiteManager().getSharedFolder());
}
CmsProperty elementReplacementProp = rootCms.readPropertyObject(
m_targetFolder,
CmsPropertyDefinition.PROPERTY_ELEMENT_REPLACEMENTS,
true);
if ((elementReplacementProp != null) && (elementReplacementProp.getValue() != null)) {
try {
CmsResource elementReplacementMap = targetCms.readResource(
elementReplacementProp.getValue(),
CmsResourceFilter.IGNORE_EXPIRATION);
OpenCms.getLocaleManager();
String encoding = CmsLocaleManager.getResourceEncoding(targetCms, elementReplacementMap);
CmsFile elementReplacementFile = targetCms.readFile(elementReplacementMap);
Properties props = new Properties();
props.load(
new InputStreamReader(new ByteArrayInputStream(elementReplacementFile.getContents()), encoding));
CmsMacroResolver resolver = new CmsMacroResolver();
resolver.addMacro("sourcesite", m_cms.getRequestContext().getSiteRoot().replaceAll("/+$", ""));
resolver.addMacro("targetsite", targetCms.getRequestContext().getSiteRoot().replaceAll("/+$", ""));
Map customReplacements = Maps.newHashMap();
for (Map.Entry