001    /**
002     * Copyright (c) 2000-present 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.dynamicdatamapping.util;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.json.JSONArray;
019    import com.liferay.portal.kernel.json.JSONFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONObject;
021    import com.liferay.portal.kernel.language.LanguageUtil;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.repository.model.FileEntry;
025    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
026    import com.liferay.portal.kernel.upload.UploadRequest;
027    import com.liferay.portal.kernel.util.ArrayUtil;
028    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
029    import com.liferay.portal.kernel.util.DateUtil;
030    import com.liferay.portal.kernel.util.FileUtil;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.HttpUtil;
033    import com.liferay.portal.kernel.util.ListUtil;
034    import com.liferay.portal.kernel.util.LocaleUtil;
035    import com.liferay.portal.kernel.util.OrderByComparator;
036    import com.liferay.portal.kernel.util.ParamUtil;
037    import com.liferay.portal.kernel.util.StringPool;
038    import com.liferay.portal.kernel.util.StringUtil;
039    import com.liferay.portal.kernel.util.UnicodeFormatter;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.model.Image;
042    import com.liferay.portal.model.Layout;
043    import com.liferay.portal.service.ImageLocalServiceUtil;
044    import com.liferay.portal.service.LayoutLocalServiceUtil;
045    import com.liferay.portal.service.ServiceContext;
046    import com.liferay.portal.theme.ThemeDisplay;
047    import com.liferay.portal.util.PortalUtil;
048    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
049    import com.liferay.portlet.documentlibrary.util.DLUtil;
050    import com.liferay.portlet.dynamicdatamapping.StructureDefinitionException;
051    import com.liferay.portlet.dynamicdatamapping.io.DDMFormJSONDeserializerUtil;
052    import com.liferay.portlet.dynamicdatamapping.io.DDMFormValuesJSONDeserializerUtil;
053    import com.liferay.portlet.dynamicdatamapping.model.DDMForm;
054    import com.liferay.portlet.dynamicdatamapping.model.DDMFormField;
055    import com.liferay.portlet.dynamicdatamapping.model.DDMFormFieldOptions;
056    import com.liferay.portlet.dynamicdatamapping.model.DDMFormLayout;
057    import com.liferay.portlet.dynamicdatamapping.model.DDMFormLayoutColumn;
058    import com.liferay.portlet.dynamicdatamapping.model.DDMFormLayoutPage;
059    import com.liferay.portlet.dynamicdatamapping.model.DDMFormLayoutRow;
060    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
061    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureVersion;
062    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
063    import com.liferay.portlet.dynamicdatamapping.model.LocalizedValue;
064    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
065    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
066    import com.liferay.portlet.dynamicdatamapping.storage.DDMFormValues;
067    import com.liferay.portlet.dynamicdatamapping.storage.Field;
068    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
069    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
070    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureIdComparator;
071    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureModifiedDateComparator;
072    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateIdComparator;
073    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateModifiedDateComparator;
074    
075    import java.io.File;
076    import java.io.Serializable;
077    
078    import java.text.DateFormat;
079    import java.text.ParseException;
080    
081    import java.util.ArrayList;
082    import java.util.Date;
083    import java.util.HashSet;
084    import java.util.Iterator;
085    import java.util.List;
086    import java.util.Locale;
087    import java.util.Map;
088    import java.util.Set;
089    
090    import javax.portlet.PortletRequest;
091    
092    import javax.servlet.http.HttpServletRequest;
093    
094    /**
095     * @author Eduardo Lundgren
096     * @author Brian Wing Shun Chan
097     * @author Eduardo Garcia
098     * @author Marcellus Tavares
099     */
100    @DoPrivileged
101    public class DDMImpl implements DDM {
102    
103            public static final String FIELDS_DISPLAY_NAME = "_fieldsDisplay";
104    
105            public static final String INSTANCE_SEPARATOR = "_INSTANCE_";
106    
107            public static final String TYPE_CHECKBOX = "checkbox";
108    
109            public static final String TYPE_DDM_DATE = "ddm-date";
110    
111            public static final String TYPE_DDM_DOCUMENTLIBRARY = "ddm-documentlibrary";
112    
113            public static final String TYPE_DDM_IMAGE = "ddm-image";
114    
115            public static final String TYPE_DDM_LINK_TO_PAGE = "ddm-link-to-page";
116    
117            public static final String TYPE_DDM_TEXT_HTML = "ddm-text-html";
118    
119            public static final String TYPE_RADIO = "radio";
120    
121            public static final String TYPE_SELECT = "select";
122    
123            @Override
124            public DDMDisplay getDDMDisplay(long classNameId) {
125                    List<DDMDisplay> ddmDisplays = DDMDisplayRegistryUtil.getDDMDisplays();
126    
127                    for (DDMDisplay ddmDisplay : ddmDisplays) {
128                            DDMPermissionHandler ddmPermissionHandler =
129                                    ddmDisplay.getDDMPermissionHandler();
130    
131                            if (ArrayUtil.contains(
132                                            ddmPermissionHandler.getResourceClassNameIds(),
133                                            classNameId)) {
134    
135                                    return ddmDisplay;
136                            }
137                    }
138    
139                    throw new IllegalArgumentException(
140                            "No DDM display registered for " +
141                                    PortalUtil.getClassName(classNameId));
142            }
143    
144            @Override
145            public DDMForm getDDMForm(long classNameId, long classPK)
146                    throws PortalException {
147    
148                    if ((classNameId <= 0) || (classPK <= 0)) {
149                            return null;
150                    }
151    
152                    long ddmStructureClassNameId = PortalUtil.getClassNameId(
153                            DDMStructure.class);
154                    long ddmTemplateClassNameId = PortalUtil.getClassNameId(
155                            DDMTemplate.class);
156    
157                    if (classNameId == ddmStructureClassNameId) {
158                            DDMStructure structure = DDMStructureLocalServiceUtil.getStructure(
159                                    classPK);
160    
161                            DDMForm ddmForm = structure.getFullHierarchyDDMForm();
162    
163                            return ddmForm;
164                    }
165                    else if (classNameId == ddmTemplateClassNameId) {
166                            DDMTemplate template = DDMTemplateLocalServiceUtil.getTemplate(
167                                    classPK);
168    
169                            return DDMFormJSONDeserializerUtil.deserialize(
170                                    template.getScript());
171                    }
172    
173                    return null;
174            }
175    
176            @Override
177            public DDMForm getDDMForm(PortletRequest portletRequest)
178                    throws PortalException {
179    
180                    try {
181                            String definition = ParamUtil.getString(
182                                    portletRequest, "definition");
183    
184                            return DDMFormJSONDeserializerUtil.deserialize(definition);
185                    }
186                    catch (PortalException pe) {
187                            throw new StructureDefinitionException(pe);
188                    }
189            }
190    
191            @Override
192            public JSONArray getDDMFormFieldsJSONArray(
193                    DDMStructure ddmStructure, String script) {
194    
195                    DDMForm ddmForm = null;
196    
197                    if (ddmStructure != null) {
198                            ddmForm = ddmStructure.getDDMForm();
199                    }
200    
201                    return getDDMFormFieldsJSONArray(ddmForm, script);
202            }
203    
204            @Override
205            public JSONArray getDDMFormFieldsJSONArray(
206                    DDMStructureVersion ddmStructureVersion, String script) {
207    
208                    DDMForm ddmForm = null;
209    
210                    if (ddmStructureVersion != null) {
211                            ddmForm = ddmStructureVersion.getDDMForm();
212                    }
213    
214                    return getDDMFormFieldsJSONArray(ddmForm, script);
215            }
216    
217            @Override
218            public DDMPermissionHandler getDDMPermissionHandler(long classNameId) {
219                    DDMDisplay ddmDisplay = getDDMDisplay(classNameId);
220    
221                    return ddmDisplay.getDDMPermissionHandler();
222            }
223    
224            @Override
225            public DDMFormLayout getDefaultDDMFormLayout(DDMForm ddmForm) {
226                    DDMFormLayout ddmFormLayout = new DDMFormLayout();
227    
228                    Locale defaultLocale = ddmForm.getDefaultLocale();
229    
230                    ddmFormLayout.setDefaultLocale(defaultLocale);
231    
232                    DDMFormLayoutPage ddmFormLayoutPage = new DDMFormLayoutPage();
233    
234                    LocalizedValue title = getDefaultDDMFormPageTitle(defaultLocale);
235    
236                    ddmFormLayoutPage.setTitle(title);
237    
238                    for (DDMFormField ddmFormField : ddmForm.getDDMFormFields()) {
239                            ddmFormLayoutPage.addDDMFormLayoutRow(
240                                    getDefaultDDMFormLayoutRow(ddmFormField));
241                    }
242    
243                    ddmFormLayout.addDDMFormLayoutPage(ddmFormLayoutPage);
244    
245                    return ddmFormLayout;
246            }
247    
248            @Override
249            public Serializable getDisplayFieldValue(
250                            ThemeDisplay themeDisplay, Serializable fieldValue, String type)
251                    throws Exception {
252    
253                    if (fieldValue instanceof Date) {
254                            Date valueDate = (Date)fieldValue;
255    
256                            DateFormat dateFormat = DateFormatFactoryUtil.getDate(
257                                    themeDisplay.getLocale());
258    
259                            fieldValue = dateFormat.format(valueDate);
260                    }
261                    else if (type.equals(DDMImpl.TYPE_CHECKBOX)) {
262                            Boolean valueBoolean = (Boolean)fieldValue;
263    
264                            if (valueBoolean) {
265                                    fieldValue = LanguageUtil.get(themeDisplay.getLocale(), "yes");
266                            }
267                            else {
268                                    fieldValue = LanguageUtil.get(themeDisplay.getLocale(), "no");
269                            }
270                    }
271                    else if (type.equals(DDMImpl.TYPE_DDM_DOCUMENTLIBRARY)) {
272                            if (Validator.isNull(fieldValue)) {
273                                    return StringPool.BLANK;
274                            }
275    
276                            String valueString = String.valueOf(fieldValue);
277    
278                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
279                                    valueString);
280    
281                            String uuid = jsonObject.getString("uuid");
282                            long groupId = jsonObject.getLong("groupId");
283    
284                            FileEntry fileEntry =
285                                    DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
286                                            uuid, groupId);
287    
288                            fieldValue = DLUtil.getPreviewURL(
289                                    fileEntry, fileEntry.getFileVersion(), null, StringPool.BLANK,
290                                    false, true);
291                    }
292                    else if (type.equals(DDMImpl.TYPE_DDM_LINK_TO_PAGE)) {
293                            if (Validator.isNull(fieldValue)) {
294                                    return StringPool.BLANK;
295                            }
296    
297                            String valueString = String.valueOf(fieldValue);
298    
299                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
300                                    valueString);
301    
302                            long groupId = jsonObject.getLong("groupId");
303                            boolean privateLayout = jsonObject.getBoolean("privateLayout");
304                            long layoutId = jsonObject.getLong("layoutId");
305    
306                            Layout layout = LayoutLocalServiceUtil.getLayout(
307                                    groupId, privateLayout, layoutId);
308    
309                            fieldValue = PortalUtil.getLayoutFriendlyURL(layout, themeDisplay);
310                    }
311                    else if (type.equals(DDMImpl.TYPE_RADIO) ||
312                                     type.equals(DDMImpl.TYPE_SELECT)) {
313    
314                            String valueString = String.valueOf(fieldValue);
315    
316                            JSONArray jsonArray = JSONFactoryUtil.createJSONArray(valueString);
317    
318                            String[] stringArray = ArrayUtil.toStringArray(jsonArray);
319    
320                            fieldValue = stringArray[0];
321                    }
322    
323                    return fieldValue;
324            }
325    
326            @Override
327            public Fields getFields(
328                            long ddmStructureId, long ddmTemplateId,
329                            ServiceContext serviceContext)
330                    throws PortalException {
331    
332                    return getFields(
333                            ddmStructureId, ddmTemplateId, StringPool.BLANK, serviceContext);
334            }
335    
336            @Override
337            public Fields getFields(
338                            long ddmStructureId, long ddmTemplateId, String fieldNamespace,
339                            ServiceContext serviceContext)
340                    throws PortalException {
341    
342                    DDMStructure ddmStructure = getDDMStructure(
343                            ddmStructureId, ddmTemplateId);
344    
345                    Set<String> fieldNames = ddmStructure.getFieldNames();
346    
347                    boolean translating = true;
348    
349                    String defaultLanguageId = (String)serviceContext.getAttribute(
350                            "defaultLanguageId");
351                    String toLanguageId = (String)serviceContext.getAttribute(
352                            "toLanguageId");
353    
354                    if (Validator.isNull(toLanguageId) ||
355                            Validator.equals(defaultLanguageId, toLanguageId)) {
356    
357                            translating = false;
358                    }
359    
360                    Fields fields = new Fields();
361    
362                    for (String fieldName : fieldNames) {
363                            boolean localizable = GetterUtil.getBoolean(
364                                    ddmStructure.getFieldProperty(fieldName, "localizable"), true);
365    
366                            if (!localizable && translating &&
367                                    !fieldName.startsWith(StringPool.UNDERLINE)) {
368    
369                                    continue;
370                            }
371    
372                            List<Serializable> fieldValues = getFieldValues(
373                                    ddmStructure, fieldName, fieldNamespace, serviceContext);
374    
375                            if ((fieldValues == null) || fieldValues.isEmpty()) {
376                                    continue;
377                            }
378    
379                            Field field = createField(
380                                    ddmStructure, fieldName, fieldValues, serviceContext);
381    
382                            fields.put(field);
383                    }
384    
385                    return fields;
386            }
387    
388            @Override
389            public Fields getFields(long ddmStructureId, ServiceContext serviceContext)
390                    throws PortalException {
391    
392                    String serializedDDMFormValues = GetterUtil.getString(
393                            serviceContext.getAttribute("ddmFormValues"));
394    
395                    if (Validator.isNotNull(serializedDDMFormValues)) {
396                            return getFields(ddmStructureId, serializedDDMFormValues);
397                    }
398    
399                    return getFields(ddmStructureId, 0, serviceContext);
400            }
401    
402            @Override
403            public Fields getFields(
404                            long ddmStructureId, String fieldNamespace,
405                            ServiceContext serviceContext)
406                    throws PortalException {
407    
408                    String serializedDDMFormValues = GetterUtil.getString(
409                            serviceContext.getAttribute(fieldNamespace + "ddmFormValues"));
410    
411                    if (Validator.isNotNull(serializedDDMFormValues)) {
412                            return getFields(ddmStructureId, serializedDDMFormValues);
413                    }
414    
415                    return getFields(ddmStructureId, 0, fieldNamespace, serviceContext);
416            }
417    
418            @Override
419            public String[] getFieldsDisplayValues(Field fieldsDisplayField)
420                    throws Exception {
421    
422                    DDMStructure ddmStructure = fieldsDisplayField.getDDMStructure();
423    
424                    List<String> fieldsDisplayValues = new ArrayList<>();
425    
426                    String[] values = splitFieldsDisplayValue(fieldsDisplayField);
427    
428                    for (String value : values) {
429                            String fieldName = StringUtil.extractFirst(
430                                    value, DDMImpl.INSTANCE_SEPARATOR);
431    
432                            if (ddmStructure.hasField(fieldName)) {
433                                    fieldsDisplayValues.add(fieldName);
434                            }
435                    }
436    
437                    return fieldsDisplayValues.toArray(
438                            new String[fieldsDisplayValues.size()]);
439            }
440    
441            @Override
442            public Serializable getIndexedFieldValue(
443                            Serializable fieldValue, String type)
444                    throws Exception {
445    
446                    if (fieldValue instanceof Date) {
447                            Date valueDate = (Date)fieldValue;
448    
449                            DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
450                                    "yyyyMMddHHmmss");
451    
452                            fieldValue = dateFormat.format(valueDate);
453                    }
454                    else if (type.equals(DDMImpl.TYPE_RADIO) ||
455                                     type.equals(DDMImpl.TYPE_SELECT)) {
456    
457                            String valueString = (String)fieldValue;
458    
459                            JSONArray jsonArray = JSONFactoryUtil.createJSONArray(valueString);
460    
461                            String[] stringArray = ArrayUtil.toStringArray(jsonArray);
462    
463                            fieldValue = stringArray[0];
464                    }
465    
466                    return fieldValue;
467            }
468    
469            @Override
470            public OrderByComparator<DDMStructure> getStructureOrderByComparator(
471                    String orderByCol, String orderByType) {
472    
473                    boolean orderByAsc = false;
474    
475                    if (orderByType.equals("asc")) {
476                            orderByAsc = true;
477                    }
478    
479                    OrderByComparator<DDMStructure> orderByComparator = null;
480    
481                    if (orderByCol.equals("id")) {
482                            orderByComparator = new StructureIdComparator(orderByAsc);
483                    }
484                    else if (orderByCol.equals("modified-date")) {
485                            orderByComparator = new StructureModifiedDateComparator(orderByAsc);
486                    }
487    
488                    return orderByComparator;
489            }
490    
491            @Override
492            public OrderByComparator<DDMTemplate> getTemplateOrderByComparator(
493                    String orderByCol, String orderByType) {
494    
495                    boolean orderByAsc = false;
496    
497                    if (orderByType.equals("asc")) {
498                            orderByAsc = true;
499                    }
500    
501                    OrderByComparator<DDMTemplate> orderByComparator = null;
502    
503                    if (orderByCol.equals("id")) {
504                            orderByComparator = new TemplateIdComparator(orderByAsc);
505                    }
506                    else if (orderByCol.equals("modified-date")) {
507                            orderByComparator = new TemplateModifiedDateComparator(orderByAsc);
508                    }
509    
510                    return orderByComparator;
511            }
512    
513            @Override
514            public Fields mergeFields(Fields newFields, Fields existingFields) {
515                    String[] newFieldsDisplayValues = splitFieldsDisplayValue(
516                            newFields.get(DDMImpl.FIELDS_DISPLAY_NAME));
517    
518                    String[] existingFieldsDisplayValues = splitFieldsDisplayValue(
519                            existingFields.get(DDMImpl.FIELDS_DISPLAY_NAME));
520    
521                    Iterator<Field> itr = newFields.iterator(true);
522    
523                    while (itr.hasNext()) {
524                            Field newField = itr.next();
525    
526                            Field existingField = existingFields.get(newField.getName());
527    
528                            if ((existingField == null) || newField.isPrivate()) {
529                                    existingFields.put(newField);
530    
531                                    continue;
532                            }
533    
534                            existingField.setDefaultLocale(newField.getDefaultLocale());
535    
536                            Map<Locale, List<Serializable>> mergedFieldValuesMap =
537                                    getMergedFieldValuesMap(
538                                            newField, newFieldsDisplayValues, existingField,
539                                            existingFieldsDisplayValues);
540    
541                            existingField.setValuesMap(mergedFieldValuesMap);
542                    }
543    
544                    return existingFields;
545            }
546    
547            protected void addDDMFormFieldLocalizedProperties(
548                    JSONObject jsonObject, DDMFormField ddmFormField, Locale locale,
549                    Locale defaultLocale) {
550    
551                    addDDMFormFieldLocalizedProperty(
552                            jsonObject, "label", ddmFormField.getLabel(), locale, defaultLocale,
553                            ddmFormField.getType());
554                    addDDMFormFieldLocalizedProperty(
555                            jsonObject, "predefinedValue", ddmFormField.getPredefinedValue(),
556                            locale, defaultLocale, ddmFormField.getType());
557                    addDDMFormFieldLocalizedProperty(
558                            jsonObject, "tip", ddmFormField.getTip(), locale, defaultLocale,
559                            ddmFormField.getType());
560            }
561    
562            protected void addDDMFormFieldLocalizedProperty(
563                    JSONObject jsonObject, String propertyName,
564                    LocalizedValue localizedValue, Locale locale, Locale defaultLocale,
565                    String type) {
566    
567                    String propertyValue = localizedValue.getString(locale);
568    
569                    if (Validator.isNull(propertyValue)) {
570                            propertyValue = localizedValue.getString(defaultLocale);
571                    }
572    
573                    if (type.equals(DDMImpl.TYPE_RADIO) ||
574                            type.equals(DDMImpl.TYPE_SELECT)) {
575    
576                            if (propertyName.equals("predefinedValue")) {
577                                    try {
578                                            jsonObject.put(
579                                                    propertyName,
580                                                    JSONFactoryUtil.createJSONArray(propertyValue));
581                                    }
582                                    catch (Exception e) {
583                                    }
584    
585                                    return;
586                            }
587                    }
588    
589                    jsonObject.put(propertyName, propertyValue);
590            }
591    
592            protected void addDDMFormFieldOptions(
593                    JSONObject jsonObject, DDMFormField ddmFormField,
594                    Set<Locale> availableLocales, Locale defaultLocale) {
595    
596                    String type = ddmFormField.getType();
597    
598                    if (!(type.equals(DDMImpl.TYPE_RADIO) ||
599                              type.equals(DDMImpl.TYPE_SELECT))) {
600    
601                            return;
602                    }
603    
604                    String fieldName = ddmFormField.getName();
605    
606                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
607    
608                    DDMFormFieldOptions ddmFormFieldOptions =
609                            ddmFormField.getDDMFormFieldOptions();
610    
611                    for (String optionValue : ddmFormFieldOptions.getOptionsValues()) {
612                            JSONObject optionJSONObject = JSONFactoryUtil.createJSONObject();
613    
614                            String name = fieldName.concat(StringUtil.randomString());
615    
616                            optionJSONObject.put("id", name);
617                            optionJSONObject.put("name", name);
618                            optionJSONObject.put("type", "option");
619                            optionJSONObject.put("value", optionValue);
620    
621                            addDDMFormFieldLocalizedProperty(
622                                    optionJSONObject, "label",
623                                    ddmFormFieldOptions.getOptionLabels(optionValue), defaultLocale,
624                                    defaultLocale, "option");
625    
626                            JSONObject localizationMapJSONObject =
627                                    JSONFactoryUtil.createJSONObject();
628    
629                            for (Locale availableLocale : availableLocales) {
630                                    JSONObject localeMap = JSONFactoryUtil.createJSONObject();
631    
632                                    addDDMFormFieldLocalizedProperty(
633                                            localeMap, "label",
634                                            ddmFormFieldOptions.getOptionLabels(optionValue),
635                                            availableLocale, defaultLocale, "option");
636    
637                                    localizationMapJSONObject.put(
638                                            LocaleUtil.toLanguageId(availableLocale), localeMap);
639                            }
640    
641                            optionJSONObject.put("localizationMap", localizationMapJSONObject);
642    
643                            jsonArray.put(optionJSONObject);
644                    }
645    
646                    jsonObject.put("options", jsonArray);
647            }
648    
649            protected int countFieldRepetition(
650                    String[] fieldsDisplayValues, String fieldName) {
651    
652                    int count = 0;
653    
654                    for (String fieldsDisplayValue : fieldsDisplayValues) {
655                            String prefix = StringUtil.extractFirst(
656                                    fieldsDisplayValue, INSTANCE_SEPARATOR);
657    
658                            if (prefix.equals(fieldName)) {
659                                    count++;
660                            }
661                    }
662    
663                    return count;
664            }
665    
666            protected Field createField(
667                    DDMStructure ddmStructure, String fieldName,
668                    List<Serializable> fieldValues, ServiceContext serviceContext) {
669    
670                    Field field = new Field();
671    
672                    field.setDDMStructureId(ddmStructure.getStructureId());
673    
674                    String languageId = GetterUtil.getString(
675                            serviceContext.getAttribute("languageId"),
676                            serviceContext.getLanguageId());
677    
678                    Locale locale = LocaleUtil.fromLanguageId(languageId);
679    
680                    String defaultLanguageId = GetterUtil.getString(
681                            serviceContext.getAttribute("defaultLanguageId"));
682    
683                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
684    
685                    if (fieldName.startsWith(StringPool.UNDERLINE)) {
686                            locale = LocaleUtil.getSiteDefault();
687    
688                            defaultLocale = LocaleUtil.getSiteDefault();
689                    }
690    
691                    field.setDefaultLocale(defaultLocale);
692    
693                    field.setName(fieldName);
694                    field.setValues(locale, fieldValues);
695    
696                    return field;
697            }
698    
699            protected JSONArray getDDMFormFieldsJSONArray(
700                    DDMForm ddmForm, String script) {
701    
702                    if (Validator.isNull(script)) {
703                            return null;
704                    }
705    
706                    JSONArray defaultDDMFormFieldsJSONArray = null;
707    
708                    if (ddmForm != null) {
709                            defaultDDMFormFieldsJSONArray = getDDMFormFieldsJSONArray(
710                                    ddmForm.getDDMFormFields(), ddmForm.getAvailableLocales(),
711                                    ddmForm.getDefaultLocale());
712                    }
713    
714                    try {
715                            DDMForm scriptDDMForm = DDMFormJSONDeserializerUtil.deserialize(
716                                    script);
717    
718                            return getDDMFormFieldsJSONArray(
719                                    scriptDDMForm.getDDMFormFields(),
720                                    scriptDDMForm.getAvailableLocales(),
721                                    scriptDDMForm.getDefaultLocale());
722                    }
723                    catch (PortalException pe) {
724                            if (_log.isWarnEnabled()) {
725                                    _log.warn("Unable to deserialize script", pe);
726                            }
727    
728                            return defaultDDMFormFieldsJSONArray;
729                    }
730            }
731    
732            protected JSONArray getDDMFormFieldsJSONArray(
733                    List<DDMFormField> ddmFormFields, Set<Locale> availableLocales,
734                    Locale defaultLocale) {
735    
736                    JSONArray ddmFormFieldsJSONArray = JSONFactoryUtil.createJSONArray();
737    
738                    for (DDMFormField ddmFormField : ddmFormFields) {
739                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
740    
741                            jsonObject.put("dataType", ddmFormField.getDataType());
742                            jsonObject.put("id", ddmFormField.getName());
743                            jsonObject.put("indexType", ddmFormField.getIndexType());
744                            jsonObject.put("localizable", ddmFormField.isLocalizable());
745                            jsonObject.put("multiple", ddmFormField.isMultiple());
746                            jsonObject.put("name", ddmFormField.getName());
747                            jsonObject.put("repeatable", ddmFormField.isRepeatable());
748                            jsonObject.put("required", ddmFormField.isRequired());
749                            jsonObject.put("showLabel", ddmFormField.isShowLabel());
750                            jsonObject.put("type", ddmFormField.getType());
751    
752                            addDDMFormFieldLocalizedProperties(
753                                    jsonObject, ddmFormField, defaultLocale, defaultLocale);
754    
755                            addDDMFormFieldOptions(
756                                    jsonObject, ddmFormField, availableLocales, defaultLocale);
757    
758                            JSONObject localizationMapJSONObject =
759                                    JSONFactoryUtil.createJSONObject();
760    
761                            for (Locale availableLocale : availableLocales) {
762                                    JSONObject localeMap = JSONFactoryUtil.createJSONObject();
763    
764                                    addDDMFormFieldLocalizedProperties(
765                                            localeMap, ddmFormField, availableLocale, defaultLocale);
766    
767                                    localizationMapJSONObject.put(
768                                            LocaleUtil.toLanguageId(availableLocale), localeMap);
769                            }
770    
771                            jsonObject.put("localizationMap", localizationMapJSONObject);
772    
773                            jsonObject.put(
774                                    "fields",
775                                    getDDMFormFieldsJSONArray(
776                                            ddmFormField.getNestedDDMFormFields(), availableLocales,
777                                            defaultLocale));
778    
779                            ddmFormFieldsJSONArray.put(jsonObject);
780                    }
781    
782                    return ddmFormFieldsJSONArray;
783            }
784    
785            protected DDMStructure getDDMStructure(
786                            long ddmStructureId, long ddmTemplateId)
787                    throws PortalException {
788    
789                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
790                            ddmStructureId);
791    
792                    DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.fetchDDMTemplate(
793                            ddmTemplateId);
794    
795                    if (ddmTemplate != null) {
796    
797                            // Clone ddmStructure to make sure changes are never persisted
798    
799                            ddmStructure = (DDMStructure)ddmStructure.clone();
800    
801                            ddmStructure.setDefinition(ddmTemplate.getScript());
802                    }
803    
804                    return ddmStructure;
805            }
806    
807            protected DDMFormLayoutRow getDefaultDDMFormLayoutRow(
808                    DDMFormField ddmFormField) {
809    
810                    DDMFormLayoutRow ddmFormLayoutRow = new DDMFormLayoutRow();
811    
812                    ddmFormLayoutRow.addDDMFormLayoutColumn(
813                            new DDMFormLayoutColumn(
814                                    DDMFormLayoutColumn.FULL, ddmFormField.getName()));
815    
816                    return ddmFormLayoutRow;
817            }
818    
819            protected LocalizedValue getDefaultDDMFormPageTitle(Locale defaultLocale) {
820                    LocalizedValue title = new LocalizedValue(defaultLocale);
821    
822                    title.addString(defaultLocale, StringPool.BLANK);
823    
824                    return title;
825            }
826    
827            protected int getExistingFieldValueIndex(
828                    String[] newFieldsDisplayValues, String[] existingFieldsDisplayValues,
829                    String fieldName, int index) {
830    
831                    String instanceId = getFieldIntanceId(
832                            newFieldsDisplayValues, fieldName, index);
833    
834                    return getFieldValueIndex(
835                            existingFieldsDisplayValues, fieldName, instanceId);
836            }
837    
838            protected String getFieldIntanceId(
839                    String[] fieldsDisplayValues, String fieldName, int index) {
840    
841                    String prefix = fieldName.concat(INSTANCE_SEPARATOR);
842    
843                    for (String fieldsDisplayValue : fieldsDisplayValues) {
844                            if (fieldsDisplayValue.startsWith(prefix)) {
845                                    index--;
846    
847                                    if (index < 0) {
848                                            return StringUtil.extractLast(
849                                                    fieldsDisplayValue, DDMImpl.INSTANCE_SEPARATOR);
850                                    }
851                            }
852                    }
853    
854                    return null;
855            }
856    
857            protected List<String> getFieldNames(
858                    String fieldNamespace, String fieldName,
859                    ServiceContext serviceContext) {
860    
861                    String[] fieldsDisplayValues = StringUtil.split(
862                            (String)serviceContext.getAttribute(
863                                    fieldNamespace + FIELDS_DISPLAY_NAME));
864    
865                    List<String> privateFieldNames = ListUtil.fromArray(
866                            new String[] {FIELDS_DISPLAY_NAME});
867    
868                    List<String> fieldNames = new ArrayList<>();
869    
870                    if ((fieldsDisplayValues.length == 0) ||
871                            privateFieldNames.contains(fieldName)) {
872    
873                            fieldNames.add(fieldNamespace + fieldName);
874                    }
875                    else {
876                            for (String namespacedFieldName : fieldsDisplayValues) {
877                                    String fieldNameValue = StringUtil.extractFirst(
878                                            namespacedFieldName, INSTANCE_SEPARATOR);
879    
880                                    if (fieldNameValue.equals(fieldName)) {
881                                            fieldNames.add(fieldNamespace + namespacedFieldName);
882                                    }
883                            }
884                    }
885    
886                    return fieldNames;
887            }
888    
889            protected Fields getFields(
890                            long ddmStructureId, String serializedDDMFormValues)
891                    throws PortalException {
892    
893                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
894                            ddmStructureId);
895    
896                    DDMFormValues ddmFormValues =
897                            DDMFormValuesJSONDeserializerUtil.deserialize(
898                                    ddmStructure.getFullHierarchyDDMForm(),
899                                    serializedDDMFormValues);
900    
901                    return DDMFormValuesToFieldsConverterUtil.convert(
902                            ddmStructure, ddmFormValues);
903            }
904    
905            protected int getFieldValueIndex(
906                    String[] fieldsDisplayValues, String fieldName, String instanceId) {
907    
908                    if (instanceId == null) {
909                            return -1;
910                    }
911    
912                    int offset = 0;
913    
914                    String prefix = fieldName.concat(INSTANCE_SEPARATOR);
915    
916                    for (String fieldsDisplayValue : fieldsDisplayValues) {
917                            if (fieldsDisplayValue.startsWith(prefix)) {
918                                    String fieldIstanceId = StringUtil.extractLast(
919                                            fieldsDisplayValue, DDMImpl.INSTANCE_SEPARATOR);
920    
921                                    if (fieldIstanceId.equals(instanceId)) {
922                                            return offset;
923                                    }
924    
925                                    offset++;
926                            }
927                    }
928    
929                    return -1;
930            }
931    
932            protected List<Serializable> getFieldValues(
933                            DDMStructure ddmStructure, String fieldName, String fieldNamespace,
934                            ServiceContext serviceContext)
935                    throws PortalException {
936    
937                    DDMFormField ddmFormField = ddmStructure.getDDMFormField(fieldName);
938    
939                    String fieldDataType = ddmFormField.getDataType();
940                    String fieldType = ddmFormField.getType();
941    
942                    LocalizedValue predefinedValue = ddmFormField.getPredefinedValue();
943    
944                    List<String> fieldNames = getFieldNames(
945                            fieldNamespace, fieldName, serviceContext);
946    
947                    List<Serializable> fieldValues = new ArrayList<>(fieldNames.size());
948    
949                    for (String fieldNameValue : fieldNames) {
950                            Serializable fieldValue = serviceContext.getAttribute(
951                                    fieldNameValue);
952    
953                            if (fieldValue == null) {
954                                    fieldValue = predefinedValue.getString(
955                                            serviceContext.getLocale());
956                            }
957    
958                            if (fieldType.equals(DDMImpl.TYPE_CHECKBOX) &&
959                                    Validator.isNull(fieldValue)) {
960    
961                                    fieldValue = "false";
962                            }
963                            else if (fieldDataType.equals(FieldConstants.DATE)) {
964                                    Date fieldValueDate = null;
965    
966                                    if (fieldValue == null) {
967                                            int fieldValueMonth = GetterUtil.getInteger(
968                                                    serviceContext.getAttribute(fieldNameValue + "Month"));
969                                            int fieldValueDay = GetterUtil.getInteger(
970                                                    serviceContext.getAttribute(fieldNameValue + "Day"));
971                                            int fieldValueYear = GetterUtil.getInteger(
972                                                    serviceContext.getAttribute(fieldNameValue + "Year"));
973    
974                                            fieldValueDate = PortalUtil.getDate(
975                                                    fieldValueMonth, fieldValueDay, fieldValueYear);
976                                    }
977                                    else {
978                                            try {
979                                                    fieldValueDate = DateUtil.parseDate(
980                                                            String.valueOf(fieldValue),
981                                                            serviceContext.getLocale());
982                                            }
983                                            catch (ParseException pe) {
984                                                    if (_log.isErrorEnabled()) {
985                                                            _log.error("Unable to parse date " + fieldValue);
986                                                    }
987                                            }
988                                    }
989    
990                                    if (fieldValueDate != null) {
991                                            fieldValue = String.valueOf(fieldValueDate.getTime());
992                                    }
993                            }
994                            else if (fieldDataType.equals(FieldConstants.IMAGE) &&
995                                             Validator.isNull(fieldValue)) {
996    
997                                    HttpServletRequest request = serviceContext.getRequest();
998    
999                                    if (request instanceof UploadRequest) {
1000                                            String imageFieldValue = getImageFieldValue(
1001                                                    (UploadRequest)request, fieldNameValue);
1002    
1003                                            if (Validator.isNotNull(imageFieldValue)) {
1004                                                    fieldValue = imageFieldValue;
1005                                            }
1006                                    }
1007                            }
1008    
1009                            if (fieldValue == null) {
1010                                    return null;
1011                            }
1012    
1013                            if (DDMImpl.TYPE_RADIO.equals(fieldType) ||
1014                                    DDMImpl.TYPE_SELECT.equals(fieldType)) {
1015    
1016                                    String predefinedValueString = predefinedValue.getString(
1017                                            serviceContext.getLocale());
1018    
1019                                    if (!fieldValue.equals(predefinedValueString) &&
1020                                            (fieldValue instanceof String)) {
1021    
1022                                            fieldValue = new String[] {String.valueOf(fieldValue)};
1023    
1024                                            fieldValue = JSONFactoryUtil.serialize(fieldValue);
1025                                    }
1026                            }
1027    
1028                            Serializable fieldValueSerializable =
1029                                    FieldConstants.getSerializable(
1030                                            fieldDataType, GetterUtil.getString(fieldValue));
1031    
1032                            fieldValues.add(fieldValueSerializable);
1033                    }
1034    
1035                    return fieldValues;
1036            }
1037    
1038            protected List<Serializable> getFieldValues(Field field, Locale locale) {
1039                    Map<Locale, List<Serializable>> fieldValuesMap = field.getValuesMap();
1040    
1041                    return fieldValuesMap.get(locale);
1042            }
1043    
1044            protected byte[] getImageBytes(
1045                            UploadRequest uploadRequest, String fieldNameValue)
1046                    throws Exception {
1047    
1048                    File file = uploadRequest.getFile(fieldNameValue + "File");
1049    
1050                    byte[] bytes = FileUtil.getBytes(file);
1051    
1052                    if (ArrayUtil.isNotEmpty(bytes)) {
1053                            return bytes;
1054                    }
1055    
1056                    String url = uploadRequest.getParameter(fieldNameValue + "URL");
1057    
1058                    long imageId = GetterUtil.getLong(
1059                            HttpUtil.getParameter(url, "img_id", false));
1060    
1061                    Image image = ImageLocalServiceUtil.fetchImage(imageId);
1062    
1063                    if (image == null) {
1064                            return null;
1065                    }
1066    
1067                    return image.getTextObj();
1068            }
1069    
1070            protected String getImageFieldValue(
1071                    UploadRequest uploadRequest, String fieldNameValue) {
1072    
1073                    try {
1074                            byte[] bytes = getImageBytes(uploadRequest, fieldNameValue);
1075    
1076                            if (ArrayUtil.isNotEmpty(bytes)) {
1077                                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
1078    
1079                                    jsonObject.put(
1080                                            "alt", uploadRequest.getParameter(fieldNameValue + "Alt"));
1081                                    jsonObject.put("data", UnicodeFormatter.bytesToHex(bytes));
1082    
1083                                    return jsonObject.toString();
1084                            }
1085                    }
1086                    catch (Exception e) {
1087                    }
1088    
1089                    return StringPool.BLANK;
1090            }
1091    
1092            protected Set<Locale> getMergedAvailableLocales(
1093                    Set<Locale> newFieldAvailableLocales,
1094                    Set<Locale> existingFieldAvailableLocales) {
1095    
1096                    Set<Locale> mergedAvailableLocales = new HashSet<>();
1097    
1098                    mergedAvailableLocales.addAll(newFieldAvailableLocales);
1099                    mergedAvailableLocales.addAll(existingFieldAvailableLocales);
1100    
1101                    return mergedAvailableLocales;
1102            }
1103    
1104            protected List<Serializable> getMergedFieldValues(
1105                    String fieldName, List<Serializable> newFieldValues,
1106                    String[] newFieldsDisplayValues, List<Serializable> existingFieldValues,
1107                    String[] existingFieldsDisplayValues,
1108                    List<Serializable> defaultFieldValues) {
1109    
1110                    if (existingFieldValues == null) {
1111                            return newFieldValues;
1112                    }
1113    
1114                    List<Serializable> mergedLocaleValues = new ArrayList<>();
1115    
1116                    int repetition = countFieldRepetition(
1117                            newFieldsDisplayValues, fieldName);
1118    
1119                    for (int i = 0; i < repetition; i++) {
1120                            int existingFieldValueIndex = getExistingFieldValueIndex(
1121                                    newFieldsDisplayValues, existingFieldsDisplayValues, fieldName,
1122                                    i);
1123    
1124                            if (existingFieldValueIndex == -1) {
1125                                    mergedLocaleValues.add(i, defaultFieldValues.get(i));
1126                            }
1127                            else {
1128                                    if (newFieldValues != null) {
1129                                            mergedLocaleValues.add(i, newFieldValues.get(i));
1130                                    }
1131                                    else {
1132                                            Serializable existingValue = existingFieldValues.get(
1133                                                    existingFieldValueIndex);
1134    
1135                                            mergedLocaleValues.add(i, existingValue);
1136                                    }
1137                            }
1138                    }
1139    
1140                    return mergedLocaleValues;
1141            }
1142    
1143            protected Map<Locale, List<Serializable>> getMergedFieldValuesMap(
1144                    Field newField, String[] newFieldsDisplayValues, Field existingField,
1145                    String[] existingFieldsDisplayValues) {
1146    
1147                    Set<Locale> availableLocales = getMergedAvailableLocales(
1148                            newField.getAvailableLocales(),
1149                            existingField.getAvailableLocales());
1150    
1151                    for (Locale locale : availableLocales) {
1152                            List<Serializable> newFieldValues = getFieldValues(
1153                                    newField, locale);
1154    
1155                            List<Serializable> existingFieldValues = getFieldValues(
1156                                    existingField, locale);
1157    
1158                            List<Serializable> defaultFieldValues = getFieldValues(
1159                                    newField, newField.getDefaultLocale());
1160    
1161                            List<Serializable> mergedLocaleValues = getMergedFieldValues(
1162                                    newField.getName(), newFieldValues, newFieldsDisplayValues,
1163                                    existingFieldValues, existingFieldsDisplayValues,
1164                                    defaultFieldValues);
1165    
1166                            existingField.setValues(locale, mergedLocaleValues);
1167                    }
1168    
1169                    return existingField.getValuesMap();
1170            }
1171    
1172            protected String[] splitFieldsDisplayValue(Field fieldsDisplayField) {
1173                    String value = (String)fieldsDisplayField.getValue();
1174    
1175                    return StringUtil.split(value);
1176            }
1177    
1178            private static final Log _log = LogFactoryUtil.getLog(DDMImpl.class);
1179    
1180    }