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.StructureXsdException;
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) throws SystemException {
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) throws SystemException {
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, SystemException {
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, SystemException {
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 throws SystemException {
179
180 Element rootElement = null;
181
182 try {
183 if (document != null) {
184 rootElement = document.getRootElement();
185 }
186 else {
187 document = SAXReaderUtil.createDocument();
188
189 rootElement = document.addElement("root");
190 }
191
192 Iterator<Field> itr = fields.iterator(true);
193
194 while (itr.hasNext()) {
195 Field field = itr.next();
196
197 List<Node> nodes = getElementsByName(document, field.getName());
198
199 for (Node node : nodes) {
200 document.remove(node);
201 }
202
203 appendField(rootElement, field);
204 }
205
206 return document.formattedString();
207 }
208 catch (IOException ioe) {
209 throw new SystemException(ioe);
210 }
211 }
212
213 @Override
214 public String getXML(Fields fields) throws SystemException {
215 return getXML(null, fields);
216 }
217
218 public void setXMLSchema(XMLSchema xmlSchema) {
219 _xmlSchema = xmlSchema;
220 }
221
222 @Override
223 public String updateXMLDefaultLocale(
224 String xml, Locale contentDefaultLocale,
225 Locale contentNewDefaultLocale)
226 throws SystemException {
227
228 try {
229 if (LocaleUtil.equals(
230 contentDefaultLocale, contentNewDefaultLocale)) {
231
232 return xml;
233 }
234
235 Document document = SAXReaderUtil.read(xml);
236
237 Element rootElement = document.getRootElement();
238
239 Attribute availableLocalesAttribute = rootElement.attribute(
240 _AVAILABLE_LOCALES);
241
242 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
243 contentNewDefaultLocale);
244
245 String availableLocalesAttributeValue =
246 availableLocalesAttribute.getValue();
247
248 if (!availableLocalesAttributeValue.contains(
249 contentNewDefaultLanguageId)) {
250
251 StringBundler sb = new StringBundler(3);
252
253 sb.append(availableLocalesAttribute.getValue());
254 sb.append(StringPool.COMMA);
255 sb.append(contentNewDefaultLanguageId);
256
257 availableLocalesAttribute.setValue(sb.toString());
258 }
259
260 Attribute defaultLocaleAttribute = rootElement.attribute(
261 _DEFAULT_LOCALE);
262
263 defaultLocaleAttribute.setValue(contentNewDefaultLanguageId);
264
265 fixElementsDefaultLocale(
266 rootElement, contentDefaultLocale, contentNewDefaultLocale);
267
268 return document.formattedString();
269 }
270 catch (DocumentException de) {
271 throw new SystemException(de);
272 }
273 catch (IOException ioe) {
274 throw new SystemException(ioe);
275 }
276 }
277
278 @Override
279 public String validateXML(String xml) throws PortalException {
280 try {
281 Document document = SAXReaderUtil.read(xml, _xmlSchema);
282
283 return document.asXML();
284 }
285 catch (Exception e) {
286 if (_log.isDebugEnabled()) {
287 _log.debug("Invalid XML content " + e.getMessage(), e);
288 }
289
290 throw new StructureXsdException();
291 }
292 }
293
294 protected void appendField(Element element, Field field) {
295 Element dynamicElementElement = element.addElement("dynamic-element");
296
297 dynamicElementElement.addAttribute(
298 "default-language-id",
299 LocaleUtil.toLanguageId(field.getDefaultLocale()));
300 dynamicElementElement.addAttribute("name", field.getName());
301
302 for (Locale locale : field.getAvailableLocales()) {
303 List<Serializable> values = field.getValues(locale);
304
305 for (Serializable value : values) {
306 Element dynamicContentElement =
307 dynamicElementElement.addElement("dynamic-content");
308
309 dynamicContentElement.addAttribute(
310 "language-id", LocaleUtil.toLanguageId(locale));
311
312 updateField(dynamicContentElement, value);
313 }
314 }
315 }
316
317 protected void fixElementsDefaultLocale(
318 Element element, Locale contentDefaultLocale,
319 Locale contentNewDefaultLocale) {
320
321 for (Element dynamicElementElement :
322 element.elements(_DYNAMIC_ELEMENT)) {
323
324 Element importMetaDataElement =
325 (Element)dynamicElementElement.selectSingleNode(
326 "meta-data[@locale='" + contentNewDefaultLocale.toString() +
327 "']");
328
329 if (importMetaDataElement == null) {
330 Element metaDataElement =
331 (Element)dynamicElementElement.selectSingleNode(
332 "meta-data[@locale='" +
333 contentDefaultLocale.toString() + "']");
334
335 Element copiedMetadataElement = metaDataElement.createCopy();
336
337 Attribute localeAttribute = copiedMetadataElement.attribute(
338 _LOCALE);
339
340 String contentNewDefaultLanguageId = LocaleUtil.toLanguageId(
341 contentNewDefaultLocale);
342
343 localeAttribute.setValue(contentNewDefaultLanguageId);
344
345 dynamicElementElement.add(copiedMetadataElement);
346 }
347
348 fixElementsDefaultLocale(
349 dynamicElementElement, contentDefaultLocale,
350 contentNewDefaultLocale);
351 }
352 }
353
354 protected List<Node> getElementsByName(Document document, String name) {
355 name = HtmlUtil.escapeXPathAttribute(name);
356
357 XPath xPathSelector = SAXReaderUtil.createXPath(
358 "
359
360 return xPathSelector.selectNodes(document);
361 }
362
363 protected void updateField(
364 Element dynamicContentElement, Serializable fieldValue) {
365
366 dynamicContentElement.clearContent();
367
368 if (fieldValue instanceof Date) {
369 Date valueDate = (Date)fieldValue;
370
371 fieldValue = valueDate.getTime();
372 }
373
374 String valueString = String.valueOf(fieldValue);
375
376 dynamicContentElement.addCDATA(valueString.trim());
377 }
378
379 private static final String _AVAILABLE_LOCALES = "available-locales";
380
381 private static final String _DEFAULT_LOCALE = "default-locale";
382
383 private static final String _DYNAMIC_ELEMENT = "dynamic-element";
384
385 private static final String _LOCALE = "locale";
386
387 private static final String _XML_INDENT = " ";
388
389 private static Log _log = LogFactoryUtil.getLog(DDMXMLImpl.class);
390
391 private XMLSchema _xmlSchema;
392
393 }