001
014
015 package com.liferay.portlet.journal.util;
016
017 import com.liferay.portal.kernel.json.JSONArray;
018 import com.liferay.portal.kernel.json.JSONFactoryUtil;
019 import com.liferay.portal.kernel.json.JSONObject;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.repository.model.FileEntry;
023 import com.liferay.portal.kernel.util.ArrayUtil;
024 import com.liferay.portal.kernel.util.CharPool;
025 import com.liferay.portal.kernel.util.GetterUtil;
026 import com.liferay.portal.kernel.util.LocaleUtil;
027 import com.liferay.portal.kernel.util.StringPool;
028 import com.liferay.portal.kernel.util.StringUtil;
029 import com.liferay.portal.kernel.util.Validator;
030 import com.liferay.portal.kernel.xml.Attribute;
031 import com.liferay.portal.kernel.xml.Document;
032 import com.liferay.portal.kernel.xml.Element;
033 import com.liferay.portal.kernel.xml.SAXReaderUtil;
034 import com.liferay.portal.kernel.xml.XPath;
035 import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
036 import com.liferay.portlet.documentlibrary.util.DLUtil;
037 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
038 import com.liferay.portlet.dynamicdatamapping.storage.Field;
039 import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
040 import com.liferay.portlet.dynamicdatamapping.storage.Fields;
041 import com.liferay.portlet.dynamicdatamapping.util.DDMFieldsCounter;
042 import com.liferay.portlet.dynamicdatamapping.util.DDMImpl;
043 import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
044 import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
045 import com.liferay.util.PwdGenerator;
046
047 import java.io.Serializable;
048
049 import java.util.Date;
050 import java.util.HashMap;
051 import java.util.List;
052 import java.util.Locale;
053 import java.util.Map;
054 import java.util.Set;
055
056
060 public class JournalConverterImpl implements JournalConverter {
061
062 public JournalConverterImpl() {
063 _ddmDataTypes = new HashMap<String, String>();
064
065 _ddmDataTypes.put("boolean", "boolean");
066 _ddmDataTypes.put("document_library", "document-library");
067 _ddmDataTypes.put("image", "image");
068 _ddmDataTypes.put("link_to_layout", "link-to-page");
069 _ddmDataTypes.put("list", "string");
070 _ddmDataTypes.put("multi-list", "string");
071 _ddmDataTypes.put("text", "string");
072 _ddmDataTypes.put("text_area", "html");
073 _ddmDataTypes.put("text_box", "string");
074
075 _ddmMetadataAttributes = new HashMap<String, String>();
076
077 _ddmMetadataAttributes.put("instructions", "tip");
078 _ddmMetadataAttributes.put("label", "label");
079 _ddmMetadataAttributes.put("predefinedValue", "predefinedValue");
080
081 _ddmTypesToJournalTypes = new HashMap<String, String>();
082
083 _ddmTypesToJournalTypes.put("checkbox", "boolean");
084 _ddmTypesToJournalTypes.put("ddm-documentlibrary", "document_library");
085 _ddmTypesToJournalTypes.put("ddm-link-to-page", "link_to_layout");
086 _ddmTypesToJournalTypes.put("ddm-text-html", "text_area");
087 _ddmTypesToJournalTypes.put("select", "list");
088 _ddmTypesToJournalTypes.put("text", "text");
089 _ddmTypesToJournalTypes.put("textarea", "text_box");
090 _ddmTypesToJournalTypes.put("wcm-image", "image");
091
092 _journalTypesToDDMTypes = new HashMap<String, String>();
093
094 _journalTypesToDDMTypes.put("boolean", "checkbox");
095 _journalTypesToDDMTypes.put("document_library", "ddm-documentlibrary");
096 _journalTypesToDDMTypes.put("image", "wcm-image");
097 _journalTypesToDDMTypes.put("link_to_layout", "ddm-link-to-page");
098 _journalTypesToDDMTypes.put("list", "select");
099 _journalTypesToDDMTypes.put("multi-list", "select");
100 _journalTypesToDDMTypes.put("text", "text");
101 _journalTypesToDDMTypes.put("text_area", "ddm-text-html");
102 _journalTypesToDDMTypes.put("text_box", "textarea");
103 }
104
105 public String getContent(DDMStructure ddmStructure, Fields ddmFields)
106 throws Exception {
107
108 Document document = SAXReaderUtil.createDocument();
109
110 Element rootElement = document.addElement("root");
111
112 String availableLocales = getAvailableLocales(ddmFields);
113
114 rootElement.addAttribute("available-locales", availableLocales);
115
116 Locale defaultLocale = ddmFields.getDefaultLocale();
117
118 rootElement.addAttribute(
119 "default-locale", LocaleUtil.toLanguageId(defaultLocale));
120
121 DDMFieldsCounter ddmFieldsCounter = new DDMFieldsCounter();
122
123 for (String fieldName : ddmStructure.getRootFieldNames()) {
124 int repetitions = countFieldRepetition(
125 ddmFields, fieldName, null, -1);
126
127 for (int i = 0; i < repetitions; i++) {
128 Element dynamicElementElement = rootElement.addElement(
129 "dynamic-element");
130
131 dynamicElementElement.addAttribute("name", fieldName);
132
133 updateContentDynamicElement(
134 dynamicElementElement, ddmStructure, ddmFields,
135 ddmFieldsCounter);
136 }
137 }
138
139 return DDMXMLUtil.formatXML(document.asXML());
140 }
141
142 public Fields getDDMFields(DDMStructure ddmStructure, String content)
143 throws Exception {
144
145 Document document = SAXReaderUtil.read(content);
146
147 Field fieldsDisplayField = new Field(
148 ddmStructure.getStructureId(), DDMImpl.FIELDS_DISPLAY_NAME,
149 StringPool.BLANK);
150
151 Fields ddmFields = new Fields();
152
153 ddmFields.put(fieldsDisplayField);
154
155 Element rootElement = document.getRootElement();
156
157 String defaultLocale = rootElement.attributeValue("default-locale");
158
159 List<Element> dynamicElementElements = rootElement.elements(
160 "dynamic-element");
161
162 for (Element dynamicElementElement : dynamicElementElements) {
163 addDDMFields(
164 dynamicElementElement, ddmStructure, ddmFields, defaultLocale);
165 }
166
167 return ddmFields;
168 }
169
170 public String getDDMXSD(String journalXSD) throws Exception {
171 Document document = SAXReaderUtil.read(journalXSD);
172
173 Element rootElement = document.getRootElement();
174
175 Locale defaultLocale = LocaleUtil.getDefault();
176
177 rootElement.addAttribute("available-locales", defaultLocale.toString());
178 rootElement.addAttribute("default-locale", defaultLocale.toString());
179
180 List<Element> dynamicElementElements = rootElement.elements(
181 "dynamic-element");
182
183 for (Element dynamicElementElement : dynamicElementElements) {
184 updateXSDDynamicElement(dynamicElementElement);
185 }
186
187 return DDMXMLUtil.formatXML(document);
188 }
189
190 protected void addDDMFields(
191 Element dynamicElementElement, DDMStructure ddmStructure,
192 Fields ddmFields, String defaultLocale)
193 throws Exception {
194
195 String name = dynamicElementElement.attributeValue("name");
196
197 if (!ddmStructure.hasField(name)) {
198 return;
199 }
200
201 Field ddmField = getField(
202 dynamicElementElement, ddmStructure, defaultLocale);
203
204 String fieldName = ddmField.getName();
205
206 Field existingDDMField = ddmFields.get(fieldName);
207
208 if (existingDDMField != null) {
209 for (Locale locale : ddmField.getAvailableLocales()) {
210 existingDDMField.addValues(locale, ddmField.getValues(locale));
211 }
212 }
213 else {
214 ddmFields.put(ddmField);
215 }
216
217 updateFieldsDisplay(ddmFields, fieldName);
218
219 List<Element> childrenDynamicElementElements =
220 dynamicElementElement.elements("dynamic-element");
221
222 for (Element childrenDynamicElementElement :
223 childrenDynamicElementElements) {
224
225 addDDMFields(
226 childrenDynamicElementElement, ddmStructure, ddmFields,
227 defaultLocale);
228 }
229 }
230
231 protected void addMetadataAttribute(
232 Element metadataElement, String name, String value) {
233
234 Element entryElement = metadataElement.addElement("entry");
235
236 entryElement.addAttribute("name", name);
237 entryElement.addCDATA(value);
238 }
239
240 protected int countFieldRepetition(
241 Fields ddmFields, String fieldName, String parentFieldName,
242 int parentOffset)
243 throws Exception {
244
245 if (!ddmFields.contains(fieldName)) {
246 return 0;
247 }
248
249 Field fieldsDisplayField = ddmFields.get(DDMImpl.FIELDS_DISPLAY_NAME);
250
251 String[] fieldsDisplayValues = DDMUtil.getFieldsDisplayValues(
252 fieldsDisplayField);
253
254 int offset = -1;
255
256 int repetitions = 0;
257
258 for (int i = 0; i < fieldsDisplayValues.length; i++) {
259 String fieldDisplayName = fieldsDisplayValues[i];
260
261 if (offset > parentOffset) {
262 break;
263 }
264
265 if (fieldDisplayName.equals(parentFieldName)) {
266 offset++;
267 }
268
269 if (fieldDisplayName.equals(fieldName) &&
270 (offset == parentOffset)) {
271
272 repetitions++;
273 }
274 }
275
276 return repetitions;
277 }
278
279 protected String getAvailableLocales(Fields ddmFields) {
280 Set<Locale> availableLocales = ddmFields.getAvailableLocales();
281
282 Locale[] availableLocalesArray = new Locale[availableLocales.size()];
283
284 availableLocalesArray = availableLocales.toArray(availableLocalesArray);
285
286 String[] languageIds = LocaleUtil.toLanguageIds(availableLocalesArray);
287
288 return StringUtil.merge(languageIds);
289 }
290
291 protected Serializable getDocumentLibraryValue(String url) {
292 try {
293 int x = url.indexOf("/documents/");
294
295 if (x == -1) {
296 return null;
297 }
298
299 int y = url.indexOf(StringPool.QUESTION);
300
301 if (y == -1) {
302 y = url.length();
303 }
304
305 url = url.substring(x, y);
306
307 String[] parts = StringUtil.split(url, CharPool.SLASH);
308
309 long groupId = GetterUtil.getLong(parts[2]);
310
311 FileEntry fileEntry =
312 DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
313 parts[5], groupId);
314
315 JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
316
317 jsonObject.put("groupId", fileEntry.getGroupId());
318 jsonObject.put("uuid", fileEntry.getUuid());
319 jsonObject.put("version", fileEntry.getVersion());
320
321 return jsonObject.toString();
322 }
323 catch (Exception e) {
324 _log.warn("Error retrieving file entry", e);
325 }
326
327 return null;
328 }
329
330 protected Field getField(
331 Element dynamicElementElement, DDMStructure ddmStructure,
332 String defaultLocale)
333 throws Exception {
334
335 Field ddmField = new Field();
336
337 ddmField.setDDMStructureId(ddmStructure.getStructureId());
338 ddmField.setDefaultLocale(LocaleUtil.fromLanguageId(defaultLocale));
339
340 String name = dynamicElementElement.attributeValue("name");
341
342 ddmField.setName(name);
343
344 String dataType = ddmStructure.getFieldDataType(name);
345 String type = ddmStructure.getFieldType(name);
346
347 List<Element> dynamicContentElements = dynamicElementElement.elements(
348 "dynamic-content");
349
350 for (Element dynamicContentElement : dynamicContentElements) {
351 Locale locale = LocaleUtil.fromLanguageId(
352 dynamicContentElement.attributeValue("language-id"));
353
354 Serializable serializable = getFieldValue(
355 dataType, type, dynamicContentElement);
356
357 ddmField.addValue(locale, serializable);
358 }
359
360 return ddmField;
361 }
362
363 protected Serializable getFieldValue(
364 String dataType, String type, Element dynamicContentElement)
365 throws Exception {
366
367 Serializable serializable = null;
368
369 if (DDMImpl.TYPE_DDM_DOCUMENTLIBRARY.equals(type)) {
370 serializable = getDocumentLibraryValue(
371 dynamicContentElement.getText());
372 }
373 else if (DDMImpl.TYPE_DDM_LINK_TO_PAGE.equals(type)) {
374 String[] values = StringUtil.split(
375 dynamicContentElement.getText(), CharPool.AT);
376
377 JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
378
379 jsonObject.put("layoutId", values[0]);
380
381 if (values[1].equals("public")) {
382 jsonObject.put("privateLayout", false);
383 }
384 else {
385 jsonObject.put("privateLayout", true);
386 }
387
388 serializable = jsonObject.toString();
389 }
390 else if (DDMImpl.TYPE_SELECT.equals(type)) {
391 JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
392
393 List<Element> optionElements = dynamicContentElement.elements(
394 "option");
395
396 if (optionElements.size() > 0) {
397 for (Element optionElement : optionElements) {
398 jsonArray.put(optionElement.getText());
399 }
400 }
401 else {
402 jsonArray.put(dynamicContentElement.getText());
403 }
404
405 serializable = jsonArray.toString();
406 }
407 else {
408 serializable = FieldConstants.getSerializable(
409 dataType, dynamicContentElement.getText());
410 }
411
412 return serializable;
413 }
414
415 protected void updateContentDynamicElement(
416 Element dynamicElementElement, DDMStructure ddmStructure,
417 Field ddmField, DDMFieldsCounter ddmFieldsCounter)
418 throws Exception {
419
420 String fieldName = ddmField.getName();
421
422 String fieldType = ddmStructure.getFieldType(fieldName);
423 String indexType = ddmStructure.getFieldProperty(
424 fieldName, "indexType");
425
426 dynamicElementElement.addAttribute(
427 "type", _ddmTypesToJournalTypes.get(fieldType));
428 dynamicElementElement.addAttribute("index-type", indexType);
429
430 for (Locale locale : ddmField.getAvailableLocales()) {
431 Element dynamicContentElement = dynamicElementElement.addElement(
432 "dynamic-content");
433
434 dynamicContentElement.addAttribute(
435 "language-id", LocaleUtil.toLanguageId(locale));
436
437 int count = ddmFieldsCounter.get(fieldName);
438
439 Serializable fieldValue = ddmField.getValue(locale, count);
440
441 if (fieldValue instanceof Date) {
442 Date valueDate = (Date)fieldValue;
443
444 fieldValue = valueDate.getTime();
445 }
446
447 String valueString = String.valueOf(fieldValue);
448
449 updateDynamicContentValue(
450 dynamicContentElement, fieldType, valueString.trim());
451 }
452
453 ddmFieldsCounter.incrementKey(fieldName);
454 }
455
456 protected void updateContentDynamicElement(
457 Element dynamicElementElement, DDMStructure ddmStructure,
458 Fields ddmFields, DDMFieldsCounter ddmFieldsCounter)
459 throws Exception {
460
461 String fieldName = dynamicElementElement.attributeValue("name");
462
463 for (String childFieldName :
464 ddmStructure.getChildrenFieldNames(fieldName)) {
465
466 int count = ddmFieldsCounter.get(fieldName);
467
468 int repetitions = countFieldRepetition(
469 ddmFields, childFieldName, fieldName, count);
470
471 for (int i = 0; i < repetitions; i++) {
472 Element childDynamicElementElement =
473 dynamicElementElement.addElement("dynamic-element");
474
475 childDynamicElementElement.addAttribute("name", childFieldName);
476
477 updateContentDynamicElement(
478 childDynamicElementElement, ddmStructure, ddmFields,
479 ddmFieldsCounter);
480 }
481 }
482
483 updateContentDynamicElement(
484 dynamicElementElement, ddmStructure, ddmFields.get(fieldName),
485 ddmFieldsCounter);
486 }
487
488 protected void updateDynamicContentValue(
489 Element dynamicContentElement, String fieldType, String fieldValue)
490 throws Exception {
491
492 if (DDMImpl.TYPE_CHECKBOX.equals(fieldType)) {
493 if (fieldValue.equals(Boolean.FALSE.toString())) {
494 fieldValue = StringPool.BLANK;
495 }
496
497 dynamicContentElement.addCDATA(fieldValue);
498 }
499 else if (DDMImpl.TYPE_DDM_DOCUMENTLIBRARY.equals(fieldType) &&
500 Validator.isNotNull(fieldValue)) {
501
502 JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
503 fieldValue);
504
505 String uuid = jsonObject.getString("uuid");
506 long groupId = jsonObject.getLong("groupId");
507
508 FileEntry fileEntry =
509 DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
510 uuid, groupId);
511
512 fieldValue = DLUtil.getPreviewURL(
513 fileEntry, fileEntry.getFileVersion(), null, StringPool.BLANK,
514 false, true);
515
516 dynamicContentElement.addCDATA(fieldValue);
517 }
518 else if (DDMImpl.TYPE_DDM_LINK_TO_PAGE.equals(fieldType) &&
519 Validator.isNotNull(fieldValue)) {
520
521 JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
522 fieldValue);
523
524 String layoutId = jsonObject.getString("layoutId");
525
526 boolean privateLayout = jsonObject.getBoolean("privateLayout");
527
528 if (privateLayout) {
529 fieldValue = layoutId.concat(StringPool.AT).concat("private");
530 }
531 else {
532 fieldValue = layoutId.concat(StringPool.AT).concat("public");
533 }
534
535 dynamicContentElement.addCDATA(fieldValue);
536 }
537 else if (DDMImpl.TYPE_SELECT.equals(fieldType) &&
538 Validator.isNotNull(fieldValue)) {
539
540 JSONArray jsonArray = JSONFactoryUtil.createJSONArray(fieldValue);
541
542 if (jsonArray.length() > 1) {
543 for (int i = 0; i <jsonArray.length(); i++) {
544 Element optionElement = dynamicContentElement.addElement(
545 "option");
546
547 optionElement.addCDATA(jsonArray.getString(i));
548 }
549 }
550 else {
551 dynamicContentElement.addCDATA(jsonArray.getString(0));
552 }
553 }
554 else {
555 dynamicContentElement.addCDATA(fieldValue);
556 }
557 }
558
559 protected void updateFieldsDisplay(Fields ddmFields, String fieldName) {
560 String fieldsDisplayValue =
561 fieldName.concat(DDMImpl.INSTANCE_SEPARATOR).concat(
562 PwdGenerator.getPassword());
563
564 Field fieldsDisplayField = ddmFields.get(DDMImpl.FIELDS_DISPLAY_NAME);
565
566 String[] fieldsDisplayValues = StringUtil.split(
567 (String)fieldsDisplayField.getValue());
568
569 fieldsDisplayValues = ArrayUtil.append(
570 fieldsDisplayValues, fieldsDisplayValue);
571
572 fieldsDisplayField.setValue(StringUtil.merge(fieldsDisplayValues));
573 }
574
575 protected void updateXSDDynamicElement(Element element) {
576 Locale defaultLocale = LocaleUtil.getDefault();
577
578 String name = element.attributeValue("name");
579 String type = element.attributeValue("type");
580
581 Element metadataElement = element.element("meta-data");
582
583 if (metadataElement == null) {
584 metadataElement = element.addElement("meta-data");
585 }
586
587 if (type.equals("multi-list")) {
588 element.addAttribute("multiple", "true");
589 }
590 else if (type.equals("selection_break")) {
591 Element parentElement = element.getParent();
592
593 parentElement.remove(element);
594
595 return;
596 }
597 else {
598 Element parentElement = element.getParent();
599
600 String parentType = parentElement.attributeValue("type");
601
602 if ((parentType != null) && parentType.equals("select")) {
603 metadataElement.addAttribute(
604 "locale", defaultLocale.toString());
605
606 addMetadataAttribute(metadataElement, "label", name);
607
608 element.addAttribute(
609 "name", "option" + PwdGenerator.getPassword(4));
610 element.addAttribute("type", "option");
611 element.addAttribute("value", type);
612
613 return;
614 }
615 }
616
617 String indexType = StringPool.BLANK;
618
619 Attribute indexTypeAttribute = element.attribute("index-type");
620
621 if (indexTypeAttribute != null) {
622 indexType = indexTypeAttribute.getValue();
623
624 element.remove(indexTypeAttribute);
625 }
626
627 element.remove(element.attribute("type"));
628
629 element.addAttribute("dataType", _ddmDataTypes.get(type));
630 element.addAttribute("indexType", indexType);
631
632 String required = "false";
633
634 XPath xPathSelector = SAXReaderUtil.createXPath(
635 "entry[@name='required']");
636
637 Element requiredElement = (Element)xPathSelector.selectSingleNode(
638 metadataElement);
639
640 if (requiredElement != null) {
641 required = requiredElement.getText();
642 }
643
644 element.addAttribute("required", required);
645
646 element.addAttribute("showLabel", "true");
647
648 String newType = _journalTypesToDDMTypes.get(type);
649
650 element.addAttribute("type", newType);
651
652 if (newType.startsWith("ddm")) {
653 element.addAttribute("fieldNamespace", "ddm");
654 }
655
656 metadataElement.addAttribute("locale", defaultLocale.toString());
657
658 List<Element> entryElements = metadataElement.elements();
659
660 if (entryElements.isEmpty()) {
661 addMetadataAttribute(metadataElement, "label", name);
662 }
663 else {
664 for (Element entryElement : entryElements) {
665 String oldEntryName = entryElement.attributeValue("name");
666
667 String newEntryName = _ddmMetadataAttributes.get(oldEntryName);
668
669 if (newEntryName == null) {
670 metadataElement.remove(entryElement);
671 }
672 else {
673 entryElement.addAttribute("name", newEntryName);
674 }
675 }
676 }
677
678 if (newType.equals("ddm-date") || newType.equals("ddm-decimal") ||
679 newType.equals("ddm-integer") ||
680 newType.equals("ddm-link-to-page") ||
681 newType.equals("ddm-number") || newType.equals("ddm-text-html") ||
682 newType.equals("text") || newType.equals("textarea")) {
683
684 element.addAttribute("width", "25");
685 }
686 else if (newType.equals("wcm-image")) {
687 element.addAttribute("fieldNamespace", "wcm");
688 element.addAttribute("readOnly", "false");
689 }
690
691 List<Element> dynamicElementElements = element.elements(
692 "dynamic-element");
693
694 for (Element dynamicElementElement : dynamicElementElements) {
695 updateXSDDynamicElement(dynamicElementElement);
696 }
697 }
698
699 private static Log _log = LogFactoryUtil.getLog(JournalConverterImpl.class);
700
701 private Map<String, String> _ddmDataTypes;
702 private Map<String, String> _ddmMetadataAttributes;
703 private Map<String, String> _ddmTypesToJournalTypes;
704 private Map<String, String> _journalTypesToDDMTypes;
705
706 }