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