001
014
015 package com.liferay.portlet.dynamicdatamapping.util;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022 import com.liferay.portal.kernel.util.HtmlUtil;
023 import com.liferay.portal.kernel.util.LocaleUtil;
024 import com.liferay.portal.kernel.util.StringBundler;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.kernel.xml.Attribute;
029 import com.liferay.portal.kernel.xml.Document;
030 import com.liferay.portal.kernel.xml.DocumentException;
031 import com.liferay.portal.kernel.xml.Element;
032 import com.liferay.portal.kernel.xml.Node;
033 import com.liferay.portal.kernel.xml.SAXReaderUtil;
034 import com.liferay.portal.kernel.xml.XMLSchema;
035 import com.liferay.portal.kernel.xml.XPath;
036 import com.liferay.portlet.dynamicdatamapping.StructureXsdException;
037 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
038 import com.liferay.portlet.dynamicdatamapping.storage.Field;
039 import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
040 import com.liferay.portlet.dynamicdatamapping.storage.Fields;
041 import com.liferay.util.xml.XMLFormatter;
042
043 import java.io.IOException;
044 import java.io.Serializable;
045
046 import java.util.Date;
047 import java.util.Iterator;
048 import java.util.List;
049 import java.util.Locale;
050
051
055 @DoPrivileged
056 public class DDMXMLImpl implements DDMXML {
057
058 @Override
059 public String formatXML(Document document) throws SystemException {
060 try {
061 return document.formattedString(_XML_INDENT);
062 }
063 catch (IOException ioe) {
064 throw new SystemException(ioe);
065 }
066 }
067
068 @Override
069 public String formatXML(String xml) throws SystemException {
070
071
072
073
074
075 try {
076 xml = StringUtil.replace(xml, "&#", "[$SPECIAL_CHARACTER$]");
077 xml = XMLFormatter.toString(xml, _XML_INDENT);
078 xml = StringUtil.replace(xml, "[$SPECIAL_CHARACTER$]", "&#");
079
080 return xml;
081 }
082 catch (IOException ioe) {
083 throw new SystemException(ioe);
084 }
085 catch (org.dom4j.DocumentException de) {
086 throw new SystemException(de);
087 }
088 }
089
090 @Override
091 public Fields getFields(DDMStructure structure, String xml)
092 throws PortalException, SystemException {
093
094 return getFields(structure, null, xml, null);
095 }
096
097 @Override
098 public Fields getFields(
099 DDMStructure structure, XPath xPath, String xml,
100 List<String> fieldNames)
101 throws PortalException, SystemException {
102
103 Document document = null;
104
105 try {
106 document = SAXReaderUtil.read(xml);
107 }
108 catch (DocumentException de) {
109 if (_log.isDebugEnabled()) {
110 _log.debug(de.getMessage(), de);
111 }
112
113 return null;
114 }
115
116 if ((xPath != null) && !xPath.booleanValueOf(document)) {
117 return null;
118 }
119
120 Fields fields = new Fields();
121
122 Element rootElement = document.getRootElement();
123
124 List<Element> dynamicElementElements = rootElement.elements(
125 "dynamic-element");
126
127 for (Element dynamicElementElement : dynamicElementElements) {
128 String fieldName = dynamicElementElement.attributeValue("name");
129
130 if (!structure.hasField(fieldName) ||
131 ((fieldNames != null) && !fieldNames.contains(fieldName))) {
132
133 continue;
134 }
135
136 String fieldDataType = structure.getFieldDataType(fieldName);
137
138 List<Element> dynamicContentElements =
139 dynamicElementElement.elements("dynamic-content");
140
141 for (Element dynamicContentElement : dynamicContentElements) {
142 String fieldValue = dynamicContentElement.getText();
143
144 String languageId = dynamicContentElement.attributeValue(
145 "language-id");
146
147 Locale locale = LocaleUtil.fromLanguageId(languageId);
148
149 Serializable fieldValueSerializable =
150 FieldConstants.getSerializable(fieldDataType, fieldValue);
151
152 Field field = fields.get(fieldName);
153
154 if (field == null) {
155 field = new Field();
156
157 String defaultLanguageId =
158 dynamicElementElement.attributeValue(
159 "default-language-id");
160
161 if (Validator.isNull(defaultLanguageId)) {
162 defaultLanguageId = rootElement.attributeValue(
163 "default-locale");
164 }
165
166 Locale defaultLocale = LocaleUtil.fromLanguageId(
167 defaultLanguageId);
168
169 field.setDefaultLocale(defaultLocale);
170
171 field.setDDMStructureId(structure.getStructureId());
172 field.setName(fieldName);
173 field.setValue(locale, fieldValueSerializable);
174
175 fields.put(field);
176 }
177 else {
178 field.addValue(locale, fieldValueSerializable);
179 }
180 }
181 }
182
183 return fields;
184 }
185
186 @Override
187 public String getXML(Document document, Fields fields)
188 throws SystemException {
189
190 Element rootElement = null;
191
192 try {
193 if (document != null) {
194 rootElement = document.getRootElement();
195 }
196 else {
197 document = SAXReaderUtil.createDocument();
198
199 rootElement = document.addElement("root");
200 }
201
202 Iterator<Field> itr = fields.iterator(true);
203
204 while (itr.hasNext()) {
205 Field field = itr.next();
206
207 List<Node> nodes = getElementsByName(document, field.getName());
208
209 for (Node node : nodes) {
210 document.remove(node);
211 }
212
213 appendField(rootElement, field);
214 }
215
216 return document.formattedString();
217 }
218 catch (IOException ioe) {
219 throw new SystemException(ioe);
220 }
221 }
222
223 @Override
224 public String getXML(Fields fields) throws SystemException {
225 return getXML(null, fields);
226 }
227
228 public void setXMLSchema(XMLSchema xmlSchema) {
229 _xmlSchema = xmlSchema;
230 }
231
232 @Override
233 public String updateXMLDefaultLocale(
234 String xml, Locale contentDefaultLocale,
235 Locale contentNewDefaultLocale)
236 throws SystemException {
237
238 try {
239 if (LocaleUtil.equals(
240 contentDefaultLocale, contentNewDefaultLocale)) {
241
242 return xml;
243 }
244
245 Document document = SAXReaderUtil.read(xml);
246
247 Element rootElement = document.getRootElement();
248
249 Attribute availableLocalesAttribute = rootElement.attribute(
250 _AVAILABLE_LOCALES);
251
252 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
253 contentNewDefaultLocale);
254
255 String availableLocalesAttributeValue =
256 availableLocalesAttribute.getValue();
257
258 if (!availableLocalesAttributeValue.contains(
259 contentNewDefaultLanguageId)) {
260
261 StringBundler sb = new StringBundler(3);
262
263 sb.append(availableLocalesAttribute.getValue());
264 sb.append(StringPool.COMMA);
265 sb.append(contentNewDefaultLanguageId);
266
267 availableLocalesAttribute.setValue(sb.toString());
268 }
269
270 Attribute defaultLocaleAttribute = rootElement.attribute(
271 _DEFAULT_LOCALE);
272
273 defaultLocaleAttribute.setValue(contentNewDefaultLanguageId);
274
275 fixElementsDefaultLocale(
276 rootElement, contentDefaultLocale, contentNewDefaultLocale);
277
278 return document.formattedString();
279 }
280 catch (DocumentException de) {
281 throw new SystemException(de);
282 }
283 catch (IOException ioe) {
284 throw new SystemException(ioe);
285 }
286 }
287
288 @Override
289 public String validateXML(String xml) throws PortalException {
290 try {
291 Document document = SAXReaderUtil.read(xml, _xmlSchema);
292
293 return document.asXML();
294 }
295 catch (Exception e) {
296 if (_log.isDebugEnabled()) {
297 _log.debug("Invalid XML content " + e.getMessage(), e);
298 }
299
300 throw new StructureXsdException(e);
301 }
302 }
303
304 protected void appendField(Element element, Field field) {
305 Element dynamicElementElement = element.addElement("dynamic-element");
306
307 dynamicElementElement.addAttribute(
308 "default-language-id",
309 LocaleUtil.toLanguageId(field.getDefaultLocale()));
310 dynamicElementElement.addAttribute("name", field.getName());
311
312 for (Locale locale : field.getAvailableLocales()) {
313 List<Serializable> values = field.getValues(locale);
314
315 for (Serializable value : values) {
316 Element dynamicContentElement =
317 dynamicElementElement.addElement("dynamic-content");
318
319 dynamicContentElement.addAttribute(
320 "language-id", LocaleUtil.toLanguageId(locale));
321
322 updateField(dynamicContentElement, value);
323 }
324 }
325 }
326
327 protected void fixElementsDefaultLocale(
328 Element element, Locale contentDefaultLocale,
329 Locale contentNewDefaultLocale) {
330
331 for (Element dynamicElementElement :
332 element.elements(_DYNAMIC_ELEMENT)) {
333
334 Element importMetaDataElement =
335 (Element)dynamicElementElement.selectSingleNode(
336 "meta-data[@locale='" + contentNewDefaultLocale.toString() +
337 "']");
338
339 if (importMetaDataElement == null) {
340 Element metaDataElement =
341 (Element)dynamicElementElement.selectSingleNode(
342 "meta-data[@locale='" +
343 contentDefaultLocale.toString() + "']");
344
345 Element copiedMetadataElement = metaDataElement.createCopy();
346
347 Attribute localeAttribute = copiedMetadataElement.attribute(
348 _LOCALE);
349
350 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
351 contentNewDefaultLocale);
352
353 localeAttribute.setValue(contentNewDefaultLanguageId);
354
355 dynamicElementElement.add(copiedMetadataElement);
356 }
357
358 fixElementsDefaultLocale(
359 dynamicElementElement, contentDefaultLocale,
360 contentNewDefaultLocale);
361 }
362 }
363
364 protected List<Node> getElementsByName(Document document, String name) {
365 name = HtmlUtil.escapeXPathAttribute(name);
366
367 XPath xPathSelector = SAXReaderUtil.createXPath(
368 "
369
370 return xPathSelector.selectNodes(document);
371 }
372
373 protected void updateField(
374 Element dynamicContentElement, Serializable fieldValue) {
375
376 dynamicContentElement.clearContent();
377
378 if (fieldValue instanceof Date) {
379 Date valueDate = (Date)fieldValue;
380
381 fieldValue = valueDate.getTime();
382 }
383
384 String valueString = String.valueOf(fieldValue);
385
386 dynamicContentElement.addCDATA(valueString.trim());
387 }
388
389 private static final String _AVAILABLE_LOCALES = "available-locales";
390
391 private static final String _DEFAULT_LOCALE = "default-locale";
392
393 private static final String _DYNAMIC_ELEMENT = "dynamic-element";
394
395 private static final String _LOCALE = "locale";
396
397 private static final String _XML_INDENT = " ";
398
399 private static Log _log = LogFactoryUtil.getLog(DDMXMLImpl.class);
400
401 private XMLSchema _xmlSchema;
402
403 }