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 return null;
110 }
111
112 if ((xPath != null) && !xPath.booleanValueOf(document)) {
113 return null;
114 }
115
116 Fields fields = new Fields();
117
118 Element rootElement = document.getRootElement();
119
120 List<Element> dynamicElementElements = rootElement.elements(
121 "dynamic-element");
122
123 for (Element dynamicElementElement : dynamicElementElements) {
124 String fieldName = dynamicElementElement.attributeValue("name");
125
126 if (!structure.hasField(fieldName) ||
127 ((fieldNames != null) && !fieldNames.contains(fieldName))) {
128
129 continue;
130 }
131
132 String fieldDataType = structure.getFieldDataType(fieldName);
133
134 List<Element> dynamicContentElements =
135 dynamicElementElement.elements("dynamic-content");
136
137 for (Element dynamicContentElement : dynamicContentElements) {
138 String fieldValue = dynamicContentElement.getText();
139
140 String languageId = dynamicContentElement.attributeValue(
141 "language-id");
142
143 Locale locale = LocaleUtil.fromLanguageId(languageId);
144
145 Serializable fieldValueSerializable =
146 FieldConstants.getSerializable(fieldDataType, fieldValue);
147
148 Field field = fields.get(fieldName);
149
150 if (field == null) {
151 field = new Field();
152
153 String defaultLanguageId =
154 dynamicElementElement.attributeValue(
155 "default-language-id");
156
157 if (Validator.isNull(defaultLanguageId)) {
158 defaultLanguageId = rootElement.attributeValue(
159 "default-locale");
160 }
161
162 Locale defaultLocale = LocaleUtil.fromLanguageId(
163 defaultLanguageId);
164
165 field.setDefaultLocale(defaultLocale);
166
167 field.setDDMStructureId(structure.getStructureId());
168 field.setName(fieldName);
169 field.setValue(locale, fieldValueSerializable);
170
171 fields.put(field);
172 }
173 else {
174 field.addValue(locale, fieldValueSerializable);
175 }
176 }
177 }
178
179 return fields;
180 }
181
182 @Override
183 public String getXML(Document document, Fields fields)
184 throws SystemException {
185
186 Element rootElement = null;
187
188 try {
189 if (document != null) {
190 rootElement = document.getRootElement();
191 }
192 else {
193 document = SAXReaderUtil.createDocument();
194
195 rootElement = document.addElement("root");
196 }
197
198 Iterator<Field> itr = fields.iterator(true);
199
200 while (itr.hasNext()) {
201 Field field = itr.next();
202
203 List<Node> nodes = getElementsByName(document, field.getName());
204
205 for (Node node : nodes) {
206 document.remove(node);
207 }
208
209 appendField(rootElement, field);
210 }
211
212 return document.formattedString();
213 }
214 catch (IOException ioe) {
215 throw new SystemException(ioe);
216 }
217 }
218
219 @Override
220 public String getXML(Fields fields) throws SystemException {
221 return getXML(null, fields);
222 }
223
224 public void setXMLSchema(XMLSchema xmlSchema) {
225 _xmlSchema = xmlSchema;
226 }
227
228 @Override
229 public String updateXMLDefaultLocale(
230 String xml, Locale contentDefaultLocale,
231 Locale contentNewDefaultLocale)
232 throws SystemException {
233
234 try {
235 if (LocaleUtil.equals(
236 contentDefaultLocale, contentNewDefaultLocale)) {
237
238 return xml;
239 }
240
241 Document document = SAXReaderUtil.read(xml);
242
243 Element rootElement = document.getRootElement();
244
245 Attribute availableLocalesAttribute = rootElement.attribute(
246 _AVAILABLE_LOCALES);
247
248 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
249 contentNewDefaultLocale);
250
251 String availableLocalesAttributeValue =
252 availableLocalesAttribute.getValue();
253
254 if (!availableLocalesAttributeValue.contains(
255 contentNewDefaultLanguageId)) {
256
257 StringBundler sb = new StringBundler(3);
258
259 sb.append(availableLocalesAttribute.getValue());
260 sb.append(StringPool.COMMA);
261 sb.append(contentNewDefaultLanguageId);
262
263 availableLocalesAttribute.setValue(sb.toString());
264 }
265
266 Attribute defaultLocaleAttribute = rootElement.attribute(
267 _DEFAULT_LOCALE);
268
269 defaultLocaleAttribute.setValue(contentNewDefaultLanguageId);
270
271 fixElementsDefaultLocale(
272 rootElement, contentDefaultLocale, contentNewDefaultLocale);
273
274 return document.formattedString();
275 }
276 catch (DocumentException de) {
277 throw new SystemException(de);
278 }
279 catch (IOException ioe) {
280 throw new SystemException(ioe);
281 }
282 }
283
284 @Override
285 public String validateXML(String xml) throws PortalException {
286 try {
287 Document document = SAXReaderUtil.read(xml, _xmlSchema);
288
289 return document.asXML();
290 }
291 catch (Exception e) {
292 if (_log.isDebugEnabled()) {
293 _log.debug("Invalid XML content " + e.getMessage(), e);
294 }
295
296 throw new StructureXsdException();
297 }
298 }
299
300 protected void appendField(Element element, Field field) {
301 Element dynamicElementElement = element.addElement("dynamic-element");
302
303 dynamicElementElement.addAttribute(
304 "default-language-id",
305 LocaleUtil.toLanguageId(field.getDefaultLocale()));
306 dynamicElementElement.addAttribute("name", field.getName());
307
308 for (Locale locale : field.getAvailableLocales()) {
309 List<Serializable> values = field.getValues(locale);
310
311 for (Serializable value : values) {
312 Element dynamicContentElement =
313 dynamicElementElement.addElement("dynamic-content");
314
315 dynamicContentElement.addAttribute(
316 "language-id", LocaleUtil.toLanguageId(locale));
317
318 updateField(dynamicContentElement, value);
319 }
320 }
321 }
322
323 protected void fixElementsDefaultLocale(
324 Element element, Locale contentDefaultLocale,
325 Locale contentNewDefaultLocale) {
326
327 for (Element dynamicElementElement :
328 element.elements(_DYNAMIC_ELEMENT)) {
329
330 Element importMetaDataElement =
331 (Element)dynamicElementElement.selectSingleNode(
332 "meta-data[@locale='" + contentNewDefaultLocale.toString() +
333 "']");
334
335 if (importMetaDataElement == null) {
336 Element metaDataElement =
337 (Element)dynamicElementElement.selectSingleNode(
338 "meta-data[@locale='" +
339 contentDefaultLocale.toString() + "']");
340
341 Element copiedMetadataElement = metaDataElement.createCopy();
342
343 Attribute localeAttribute = copiedMetadataElement.attribute(
344 _LOCALE);
345
346 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
347 contentNewDefaultLocale);
348
349 localeAttribute.setValue(contentNewDefaultLanguageId);
350
351 dynamicElementElement.add(copiedMetadataElement);
352 }
353
354 fixElementsDefaultLocale(
355 dynamicElementElement, contentDefaultLocale,
356 contentNewDefaultLocale);
357 }
358 }
359
360 protected List<Node> getElementsByName(Document document, String name) {
361 name = HtmlUtil.escapeXPathAttribute(name);
362
363 XPath xPathSelector = SAXReaderUtil.createXPath(
364 "
365
366 return xPathSelector.selectNodes(document);
367 }
368
369 protected void updateField(
370 Element dynamicContentElement, Serializable fieldValue) {
371
372 dynamicContentElement.clearContent();
373
374 if (fieldValue instanceof Date) {
375 Date valueDate = (Date)fieldValue;
376
377 fieldValue = valueDate.getTime();
378 }
379
380 String valueString = String.valueOf(fieldValue);
381
382 dynamicContentElement.addCDATA(valueString.trim());
383 }
384
385 private static final String _AVAILABLE_LOCALES = "available-locales";
386
387 private static final String _DEFAULT_LOCALE = "default-locale";
388
389 private static final String _DYNAMIC_ELEMENT = "dynamic-element";
390
391 private static final String _LOCALE = "locale";
392
393 private static final String _XML_INDENT = " ";
394
395 private static Log _log = LogFactoryUtil.getLog(DDMXMLImpl.class);
396
397 private XMLSchema _xmlSchema;
398
399 }