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