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