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

com.liferay.dynamic.data.mapping.internal.util.DDMXMLImpl Maven / Gradle / Ivy

/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

package com.liferay.dynamic.data.mapping.internal.util;

import com.liferay.dynamic.data.mapping.constants.DDMStructureConstants;
import com.liferay.dynamic.data.mapping.exception.StructureDefinitionException;
import com.liferay.dynamic.data.mapping.exception.StructureDuplicateElementException;
import com.liferay.dynamic.data.mapping.model.DDMStructure;
import com.liferay.dynamic.data.mapping.storage.Field;
import com.liferay.dynamic.data.mapping.storage.Fields;
import com.liferay.dynamic.data.mapping.storage.constants.FieldConstants;
import com.liferay.dynamic.data.mapping.util.DDMXML;
import com.liferay.petra.string.StringBundler;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.HtmlUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.DocumentException;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.Node;
import com.liferay.portal.kernel.xml.SAXReader;
import com.liferay.portal.kernel.xml.XMLSchema;
import com.liferay.portal.kernel.xml.XPath;
import com.liferay.portal.xml.XMLSchemaImpl;

import java.io.IOException;
import java.io.Serializable;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
 * @author Bruno Basto
 * @author Brian Wing Shun Chan
 */
@Component(service = DDMXML.class)
public class DDMXMLImpl implements DDMXML {

	@Override
	public Fields getFields(DDMStructure structure, String xml)
		throws PortalException {

		return getFields(structure, null, xml, null);
	}

	@Override
	public Fields getFields(
			DDMStructure structure, XPath xPath, String xml,
			List fieldNames)
		throws PortalException {

		Document document = null;

		try {
			document = _saxReader.read(xml);
		}
		catch (DocumentException documentException) {
			if (_log.isDebugEnabled()) {
				_log.debug(documentException);
			}

			return null;
		}

		if ((xPath != null) && !xPath.booleanValueOf(document)) {
			return null;
		}

		Fields fields = new Fields();

		Element rootElement = document.getRootElement();

		List dynamicElementElements = rootElement.elements(
			"dynamic-element");

		for (Element dynamicElementElement : dynamicElementElements) {
			String fieldName = dynamicElementElement.attributeValue("name");

			if (!structure.hasField(fieldName) ||
				((fieldNames != null) && !fieldNames.contains(fieldName))) {

				continue;
			}

			String fieldDataType = structure.getFieldDataType(fieldName);

			List dynamicContentElements =
				dynamicElementElement.elements("dynamic-content");

			for (Element dynamicContentElement : dynamicContentElements) {
				String fieldValue = dynamicContentElement.getText();

				String languageId = dynamicContentElement.attributeValue(
					"language-id");

				Locale locale = LocaleUtil.fromLanguageId(languageId);

				Serializable fieldValueSerializable =
					FieldConstants.getSerializable(fieldDataType, fieldValue);

				Field field = fields.get(fieldName);

				if (field == null) {
					field = new Field();

					String defaultLanguageId =
						dynamicElementElement.attributeValue(
							"default-language-id");

					if (Validator.isNull(defaultLanguageId)) {
						defaultLanguageId = rootElement.attributeValue(
							"default-locale");
					}

					field.setDefaultLocale(
						LocaleUtil.fromLanguageId(defaultLanguageId));
					field.setDDMStructureId(structure.getStructureId());
					field.setName(fieldName);
					field.setValue(locale, fieldValueSerializable);

					fields.put(field);
				}
				else {
					field.addValue(locale, fieldValueSerializable);
				}
			}
		}

		return fields;
	}

	@Override
	public String getXML(Document document, Fields fields) {
		Element rootElement = null;

		try {
			if (document != null) {
				rootElement = document.getRootElement();
			}
			else {
				document = _saxReader.createDocument();

				rootElement = document.addElement("root");
			}

			Iterator iterator = fields.iterator(true);

			while (iterator.hasNext()) {
				Field field = iterator.next();

				List nodes = _getElementsByName(
					document, field.getName());

				for (Node node : nodes) {
					document.remove(node);
				}

				_appendField(rootElement, field);
			}

			return document.formattedString();
		}
		catch (IOException ioException) {
			throw new SystemException(ioException);
		}
	}

	@Override
	public String getXML(Fields fields) {
		return getXML(null, fields);
	}

	public XMLSchema getXMLSchema() {
		if (_xmlSchema == null) {
			XMLSchemaImpl xmlSchemaImpl = new XMLSchemaImpl();

			xmlSchemaImpl.setSchemaLanguage("http://www.w3.org/2001/XMLSchema");
			xmlSchemaImpl.setSystemId(
				"http://www.liferay.com/dtd/liferay-ddm-structure_6_2_0.xsd");

			_xmlSchema = xmlSchemaImpl;
		}

		return _xmlSchema;
	}

	@Override
	public String validateXML(String xml) throws PortalException {
		try {
			Document document = _saxReader.read(xml, getXMLSchema());

			_validate(document);

			return document.asXML();
		}
		catch (StructureDefinitionException structureDefinitionException) {
			throw structureDefinitionException;
		}
		catch (StructureDuplicateElementException
					structureDuplicateElementException) {

			throw structureDuplicateElementException;
		}
		catch (Exception exception) {
			if (_log.isDebugEnabled()) {
				_log.debug(
					"Invalid XML content " + exception.getMessage(), exception);
			}

			throw new StructureDefinitionException(exception);
		}
	}

	private void _appendField(Element element, Field field) {
		Element dynamicElementElement = element.addElement("dynamic-element");

		dynamicElementElement.addAttribute(
			"default-language-id",
			LocaleUtil.toLanguageId(field.getDefaultLocale()));
		dynamicElementElement.addAttribute("name", field.getName());

		for (Locale locale : field.getAvailableLocales()) {
			List values = field.getValues(locale);

			for (Serializable value : values) {
				Element dynamicContentElement =
					dynamicElementElement.addElement("dynamic-content");

				dynamicContentElement.addAttribute(
					"language-id", LocaleUtil.toLanguageId(locale));

				_updateField(dynamicContentElement, value);
			}
		}
	}

	private List _getElementsByName(Document document, String name) {
		name = HtmlUtil.escapeXPathAttribute(name);

		XPath xPathSelector = _saxReader.createXPath(
			StringBundler.concat("//dynamic-element[@name=", name, "]"));

		return xPathSelector.selectNodes(document);
	}

	private void _updateField(
		Element dynamicContentElement, Serializable fieldValue) {

		dynamicContentElement.clearContent();

		if (fieldValue instanceof Date) {
			Date valueDate = (Date)fieldValue;

			fieldValue = valueDate.getTime();
		}

		String valueString = String.valueOf(fieldValue);

		dynamicContentElement.addCDATA(valueString.trim());
	}

	private void _validate(Document document) throws Exception {
		XPath xPathSelector = _saxReader.createXPath("//dynamic-element");

		List nodes = xPathSelector.selectNodes(document);

		Set elementNames = new HashSet<>();

		for (Node node : nodes) {
			Element element = (Element)node;

			String name = StringUtil.toLowerCase(
				element.attributeValue("name"));

			if (Validator.isNull(name)) {
				throw new StructureDefinitionException(
					"Element must have a name attribute " +
						element.formattedString());
			}

			if (name.startsWith(DDMStructureConstants.XSD_NAME_RESERVED)) {
				throw new StructureDefinitionException(
					"Element name " + name + " is reserved");
			}

			if (elementNames.contains(name)) {
				throw new StructureDuplicateElementException(
					"Element with name " + name + " already exists");
			}

			elementNames.add(name);
		}
	}

	private static final Log _log = LogFactoryUtil.getLog(DDMXMLImpl.class);

	@Reference
	private SAXReader _saxReader;

	private XMLSchema _xmlSchema;

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy