com.liferay.dynamic.data.mapping.internal.util.DDMXMLImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.dynamic.data.mapping.internal.util.DDMXMLImpl.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * 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.
 */

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

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.model.DDMStructureConstants;
import com.liferay.dynamic.data.mapping.storage.Field;
import com.liferay.dynamic.data.mapping.storage.FieldConstants;
import com.liferay.dynamic.data.mapping.storage.Fields;
import com.liferay.dynamic.data.mapping.util.DDMXML;
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.security.pacl.DoPrivileged;
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(immediate = true)
@DoPrivileged
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<String> fieldNames)
            throws PortalException {

        Document document = null;

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

            return null;
        }

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

        Fields fields = new Fields();

        Element rootElement = document.getRootElement();

        List<Element> 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<Element> 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");
                    }

                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);

                    field.setDefaultLocale(defaultLocale);

                    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<Field> itr = fields.iterator(true);

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

                List<Node> nodes = getElementsByName(document, field.getName());

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

                appendField(rootElement, field);
            }

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

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

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

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

            _xmlSchema = xmlSchema;
        }

        return _xmlSchema;
    }

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

            validate(document);

            return document.asXML();
        } catch (StructureDefinitionException sde) {
            throw sde;
        } catch (StructureDuplicateElementException sdee) {
            throw sdee;
        } catch (Exception e) {
            if (_log.isDebugEnabled()) {
                _log.debug("Invalid XML content " + e.getMessage(), e);
            }

            throw new StructureDefinitionException(e);
        }
    }

    protected 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<Serializable> values = field.getValues(locale);

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

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

                updateField(dynamicContentElement, value);
            }
        }
    }

    protected List<Node> getElementsByName(Document document, String name) {
        name = HtmlUtil.escapeXPathAttribute(name);

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

        return xPathSelector.selectNodes(document);
    }

    @Reference(unbind = "-")
    protected void setSAXReader(SAXReader saxReader) {
        _saxReader = saxReader;
    }

    protected 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());
    }

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

        List<Node> nodes = xPathSelector.selectNodes(document);

        Set<String> 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);

    private SAXReader _saxReader;
    private XMLSchema _xmlSchema;

}