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