All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.xml.page.CmsXmlPage Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * 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 GmbH & Co. KG, 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.page;

import org.opencms.configuration.CmsConfigurationManager;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.i18n.CmsEncoder;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.main.CmsIllegalArgumentException;
import org.opencms.main.CmsLog;
import org.opencms.main.CmsRuntimeException;
import org.opencms.staticexport.CmsLinkProcessor;
import org.opencms.staticexport.CmsLinkTable;
import org.opencms.xml.A_CmsXmlDocument;
import org.opencms.xml.CmsXmlContentDefinition;
import org.opencms.xml.CmsXmlEntityResolver;
import org.opencms.xml.CmsXmlException;
import org.opencms.xml.CmsXmlGenericWrapper;
import org.opencms.xml.CmsXmlUtils;
import org.opencms.xml.content.CmsXmlContentErrorHandler;
import org.opencms.xml.content.I_CmsXmlContentHandler;
import org.opencms.xml.types.CmsXmlHtmlValue;
import org.opencms.xml.types.I_CmsXmlContentValue;
import org.opencms.xml.types.I_CmsXmlSchemaType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.xml.sax.InputSource;

/**
 * Implementation of a page object used to access and manage xml data.

* * This implementation consists of several named elements optionally available for * various languages. The data of each element is accessible via its name and language. * * The content of each element is stored as CDATA, links within the * content are processed and are separately accessible as entries of a CmsLinkTable. * * @since 6.0.0 */ public class CmsXmlPage extends A_CmsXmlDocument { /** Name of the name attribute of the elements node. */ public static final String ATTRIBUTE_ENABLED = "enabled"; /** Name of the language attribute of the elements node. */ public static final String ATTRIBUTE_LANGUAGE = "language"; /** Name of the name attribute of the elements node. */ public static final String ATTRIBUTE_NAME = "name"; /** Name of the element node. */ public static final String NODE_CONTENT = "content"; /** Name of the elements node. */ public static final String NODE_ELEMENTS = "elements"; /** Name of the link node. */ public static final String NODE_LINK = "link"; /** Name of the links node. */ public static final String NODE_LINKS = "links"; /** Name of the page node. */ public static final String NODE_PAGE = "page"; /** Name of the page node. */ public static final String NODE_PAGES = "pages"; /** Property to check if relative links are allowed. */ public static final String PROPERTY_ALLOW_RELATIVE = "allowRelativeLinks"; /** The DTD address of the OpenCms xmlpage. */ public static final String XMLPAGE_XSD_SYSTEM_ID = CmsConfigurationManager.DEFAULT_DTD_PREFIX + "xmlpage.xsd"; /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsXmlPage.class); /** The XML page content definition is static. */ private static CmsXmlContentDefinition m_xmlPageContentDefinition; /** Name of the element node. */ private static final String NODE_ELEMENT = "element"; /** Indicates if relative Links are allowed. */ private boolean m_allowRelativeLinks; /** * Creates a new CmsXmlPage based on the provided document and encoding.

* * The encoding is used for marshalling the XML document later.

* * @param document the document to create the CmsXmlPage from * @param encoding the encoding of the xml page */ public CmsXmlPage(Document document, String encoding) { initDocument(document, encoding, getContentDefinition()); } /** * Creates an empty XML page in the provided locale using * the provided encoding.

* * The page is initialized according to the minimal necessary xml structure. * The encoding is used for marshalling the XML document later.

* * @param locale the initial locale of the XML page * @param encoding the encoding of the XML page */ public CmsXmlPage(Locale locale, String encoding) { initDocument(CmsXmlPageFactory.createDocument(locale), encoding, getContentDefinition()); } /** * @see org.opencms.xml.I_CmsXmlDocument#addLocale(org.opencms.file.CmsObject, java.util.Locale) */ public void addLocale(CmsObject cms, Locale locale) throws CmsXmlException { if (hasLocale(locale)) { throw new CmsXmlException(Messages.get().container(Messages.ERR_XML_PAGE_LOCALE_EXISTS_1, locale)); } // add element node for Locale getContentDefinition().createLocale(cms, this, m_document.getRootElement(), locale); // re-initialize the bookmarks initDocument(m_document, m_encoding, getContentDefinition()); } /** * Adds a new, empty value with the given name and locale * to this XML document.

* * @param name the name of the value * @param locale the locale of the value * * @throws CmsIllegalArgumentException if the name contains an index ("[<number>]") or the value for the * given locale already exists in the xmlpage. * */ public void addValue(String name, Locale locale) throws CmsIllegalArgumentException { if (name.indexOf('[') >= 0) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_XML_PAGE_CONTAINS_INDEX_1, name)); } if (hasValue(name, locale)) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_XML_PAGE_LANG_ELEM_EXISTS_2, name, locale)); } Element pages = m_document.getRootElement(); String localeStr = locale.toString(); Element page = null; // search if a page for the selected language is already available for (Iterator i = CmsXmlGenericWrapper.elementIterator(pages, NODE_PAGE); i.hasNext();) { Element nextPage = i.next(); String language = nextPage.attributeValue(ATTRIBUTE_LANGUAGE); if (localeStr.equals(language)) { // a page for the selected language was found page = nextPage; break; } } // create the new element Element element; if (page != null) { // page for selected language already available element = page.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, name); } else { // no page for the selected language was found element = pages.addElement(NODE_PAGE).addAttribute(ATTRIBUTE_LANGUAGE, localeStr); element = element.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, name); } // add empty nodes for link table and content to the element element.addElement(NODE_LINKS); element.addElement(NODE_CONTENT); CmsXmlHtmlValue value = new CmsXmlHtmlValue(this, element, locale); // bookmark the element addBookmark(CmsXmlUtils.createXpathElement(name, 1), locale, true, value); } /** * Returns if relative links are accepted (and left unprocessed).

* * @return true if relative links are allowed */ public boolean getAllowRelativeLinks() { return m_allowRelativeLinks; } /** * @see org.opencms.xml.I_CmsXmlDocument#getContentDefinition() */ public CmsXmlContentDefinition getContentDefinition() throws CmsRuntimeException { if (m_xmlPageContentDefinition == null) { // since XML page schema is cached anyway we don't need an CmsObject instance CmsXmlEntityResolver resolver = new CmsXmlEntityResolver(null); InputSource source; try { source = resolver.resolveEntity(null, XMLPAGE_XSD_SYSTEM_ID); // store content definition in static variable m_xmlPageContentDefinition = CmsXmlContentDefinition.unmarshal(source, XMLPAGE_XSD_SYSTEM_ID, resolver); } catch (CmsXmlException e) { throw new CmsRuntimeException( Messages.get().container(Messages.ERR_XML_PAGE_UNMARSHAL_CONTENDDEF_0), e); } } return m_xmlPageContentDefinition; } /** * @see org.opencms.xml.I_CmsXmlDocument#getHandler() */ public I_CmsXmlContentHandler getHandler() { return getContentDefinition().getContentHandler(); } /** * @see org.opencms.xml.A_CmsXmlDocument#getLinkProcessor(org.opencms.file.CmsObject, org.opencms.staticexport.CmsLinkTable) */ public CmsLinkProcessor getLinkProcessor(CmsObject cms, CmsLinkTable linkTable) { // initialize link processor String relativeRoot = null; if ((!m_allowRelativeLinks) && (m_file != null)) { relativeRoot = CmsResource.getParentFolder(cms.getSitePath(m_file)); } return new CmsLinkProcessor(cms, linkTable, getEncoding(), relativeRoot); } /** * Returns the link table of an element.

* * @param name name of the element * @param locale locale of the element * @return the link table */ public CmsLinkTable getLinkTable(String name, Locale locale) { CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale); if (value != null) { return value.getLinkTable(); } return new CmsLinkTable(); } /** * @see org.opencms.xml.A_CmsXmlDocument#getNames(java.util.Locale) */ @Override public List getNames(Locale locale) { Set sn = m_elementNames.get(locale); if (sn != null) { List result = new ArrayList(); Iterator i = sn.iterator(); while (i.hasNext()) { String path = i.next(); result.add(CmsXmlUtils.removeXpathIndex(path)); } return result; } return Collections.emptyList(); } /** * Checks if the element of a page object is enabled.

* * @param name the name of the element * @param locale the locale of the element * @return true if the element exists and is not disabled */ @Override public boolean isEnabled(String name, Locale locale) { CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale); if (value != null) { Element element = value.getElement(); Attribute enabled = element.attribute(ATTRIBUTE_ENABLED); return ((enabled == null) || Boolean.valueOf(enabled.getValue()).booleanValue()); } return false; } /** * Removes an existing value with the given name and locale * from this XML document.

* * @param name the name of the value * @param locale the locale of the value */ public void removeValue(String name, Locale locale) { I_CmsXmlContentValue value = removeBookmark(CmsXmlUtils.createXpath(name, 1), locale); if (value != null) { Element element = value.getElement(); element.detach(); } } /** * Renames the page-element value from the old to the new one.

* * @param oldValue the old value * @param newValue the new value * @param locale the locale * * @throws CmsIllegalArgumentException if the name contains an index ("[<number>]"), the new value for the * given locale already exists in the xmlpage or the the old value does not exist for the locale in the xmlpage. * */ public void renameValue(String oldValue, String newValue, Locale locale) throws CmsIllegalArgumentException { CmsXmlHtmlValue oldXmlHtmlValue = (CmsXmlHtmlValue)getValue(oldValue, locale); if (oldXmlHtmlValue == null) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_XML_PAGE_NO_ELEM_FOR_LANG_2, oldValue, locale)); } if (hasValue(newValue, locale)) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_XML_PAGE_LANG_ELEM_EXISTS_2, newValue, locale)); } if (newValue.indexOf('[') >= 0) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_XML_PAGE_CONTAINS_INDEX_1, newValue)); } // get the element Element element = oldXmlHtmlValue.getElement(); // update value of the element attribute 'NAME' element.addAttribute(ATTRIBUTE_NAME, newValue); // re-initialize the document to update the bookmarks initDocument(m_document, m_encoding, getContentDefinition()); } /** * Sets the enabled flag of an already existing element.

* * Note: if isEnabled is set to true, the attribute is removed * since true is the default * * @param name name name of the element * @param locale locale of the element * @param isEnabled enabled flag for the element */ public void setEnabled(String name, Locale locale, boolean isEnabled) { CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale); Element element = value.getElement(); Attribute enabled = element.attribute(ATTRIBUTE_ENABLED); if (enabled == null) { if (!isEnabled) { element.addAttribute(ATTRIBUTE_ENABLED, Boolean.toString(isEnabled)); } } else if (isEnabled) { element.remove(enabled); } else { enabled.setValue(Boolean.toString(isEnabled)); } } /** * Sets the data of an already existing value.

* * The data will be enclosed as CDATA within the xml page structure. * When setting the element data, the content of this element will be * processed automatically.

* * @param cms the cms object * @param name name of the element * @param locale locale of the element * @param content character data (CDATA) of the element * * @throws CmsXmlException if something goes wrong */ public void setStringValue(CmsObject cms, String name, Locale locale, String content) throws CmsXmlException { CmsXmlHtmlValue value = (CmsXmlHtmlValue)getValue(name, locale); if (value != null) { // set the values value.setStringValue(cms, content); } else { throw new CmsXmlException( Messages.get().container(Messages.ERR_XML_PAGE_INVALID_ELEM_SELECT_2, locale, name)); } } /** * @see org.opencms.xml.I_CmsXmlDocument#validate(org.opencms.file.CmsObject) */ public CmsXmlContentErrorHandler validate(CmsObject cms) { // XML pages currently do not support validation return new CmsXmlContentErrorHandler(); } /** * @see org.opencms.xml.A_CmsXmlDocument#initDocument(org.dom4j.Document, java.lang.String, org.opencms.xml.CmsXmlContentDefinition) */ @Override protected void initDocument(Document document, String encoding, CmsXmlContentDefinition definition) { m_encoding = CmsEncoder.lookupEncoding(encoding, encoding); m_document = document; m_elementLocales = new HashMap>(); m_elementNames = new HashMap>(); m_locales = new HashSet(); // convert pre 5.3.6 XML page documents if (!NODE_PAGES.equals(m_document.getRootElement().getName())) { convertOldDocument(); } // initialize the bookmarks clearBookmarks(); Element pages = m_document.getRootElement(); try { for (Iterator i = CmsXmlGenericWrapper.elementIterator(pages, NODE_PAGE); i.hasNext();) { Element page = i.next(); Locale locale = CmsLocaleManager.getLocale(page.attributeValue(ATTRIBUTE_LANGUAGE)); for (Iterator j = CmsXmlGenericWrapper.elementIterator(page, NODE_ELEMENT); j.hasNext();) { Element element = j.next(); String name = element.attributeValue(ATTRIBUTE_NAME); String elementEnabled = element.attributeValue(ATTRIBUTE_ENABLED); boolean enabled = (elementEnabled == null) ? true : Boolean.valueOf(elementEnabled).booleanValue(); // create an element type from the XML node CmsXmlHtmlValue value = new CmsXmlHtmlValue(this, element, locale); value.setContentDefinition(definition); // add the element type bookmark addBookmark(CmsXmlUtils.createXpathElement(name, 1), locale, enabled, value); } addLocale(locale); } } catch (NullPointerException e) { LOG.error(Messages.get().getBundle().key(Messages.ERR_XML_PAGE_INIT_BOOKMARKS_0), e); } } /** * Sets the parameter that controls the relative link generation.

* * @param value the parameter that controls the relative link generation */ protected void setAllowRelativeLinks(boolean value) { m_allowRelativeLinks = value; } /** * Sets the file this XML page content is written to.

* * @param file the file this XML page content is written to */ protected void setFile(CmsFile file) { m_file = file; } /** * Converts the XML structure of the pre 5.5.0 development version of * the XML page to the final 6.0 version.

*/ private void convertOldDocument() { Document newDocument = DocumentHelper.createDocument(); Element root = newDocument.addElement(NODE_PAGES); root.add(I_CmsXmlSchemaType.XSI_NAMESPACE); root.addAttribute(I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION, XMLPAGE_XSD_SYSTEM_ID); Map pages = new HashMap(); if ((m_document.getRootElement() != null) && (m_document.getRootElement().element(NODE_ELEMENTS) != null)) { for (Iterator i = CmsXmlGenericWrapper.elementIterator( m_document.getRootElement().element(NODE_ELEMENTS), NODE_ELEMENT); i.hasNext();) { Element elem = i.next(); try { String elementName = elem.attributeValue(ATTRIBUTE_NAME); String elementLang = elem.attributeValue(ATTRIBUTE_LANGUAGE); String elementEnabled = elem.attributeValue(ATTRIBUTE_ENABLED); boolean enabled = (elementEnabled == null) ? true : Boolean.valueOf(elementEnabled).booleanValue(); Element page = pages.get(elementLang); if (page == null) { // no page available for the language, add one page = root.addElement(NODE_PAGE).addAttribute(ATTRIBUTE_LANGUAGE, elementLang); pages.put(elementLang, page); } Element newElement = page.addElement(NODE_ELEMENT).addAttribute(ATTRIBUTE_NAME, elementName); if (!enabled) { newElement.addAttribute(ATTRIBUTE_ENABLED, String.valueOf(enabled)); } Element links = elem.element(NODE_LINKS); if (links != null) { newElement.add(links.createCopy()); } Element content = elem.element(NODE_CONTENT); if (content != null) { newElement.add(content.createCopy()); } } catch (NullPointerException e) { LOG.error(Messages.get().getBundle().key(Messages.ERR_XML_PAGE_CONVERT_CONTENT_0), e); } } } // now replace the old with the new document m_document = newDocument; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy