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