001    /**
002     * Copyright (c) 2000-2013 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.exception.SystemException;
019    import com.liferay.portal.kernel.json.JSONArray;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
022    import com.liferay.portal.kernel.language.LanguageUtil;
023    import com.liferay.portal.kernel.repository.model.FileEntry;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.upload.UploadRequest;
026    import com.liferay.portal.kernel.util.ArrayUtil;
027    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
028    import com.liferay.portal.kernel.util.FileUtil;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.ListUtil;
031    import com.liferay.portal.kernel.util.LocaleUtil;
032    import com.liferay.portal.kernel.util.OrderByComparator;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.StringUtil;
035    import com.liferay.portal.kernel.util.UnicodeFormatter;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Layout;
038    import com.liferay.portal.service.LayoutLocalServiceUtil;
039    import com.liferay.portal.service.ServiceContext;
040    import com.liferay.portal.theme.ThemeDisplay;
041    import com.liferay.portal.util.PortalUtil;
042    import com.liferay.portal.util.PropsValues;
043    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
044    import com.liferay.portlet.documentlibrary.util.DLUtil;
045    import com.liferay.portlet.dynamicdatamapping.NoSuchTemplateException;
046    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
047    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
048    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
049    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
050    import com.liferay.portlet.dynamicdatamapping.storage.Field;
051    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
052    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
053    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureIdComparator;
054    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureModifiedDateComparator;
055    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateIdComparator;
056    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateModifiedDateComparator;
057    
058    import java.io.File;
059    import java.io.IOException;
060    import java.io.Serializable;
061    
062    import java.text.DateFormat;
063    
064    import java.util.ArrayList;
065    import java.util.Date;
066    import java.util.Iterator;
067    import java.util.List;
068    import java.util.Locale;
069    import java.util.Set;
070    
071    import javax.servlet.http.HttpServletRequest;
072    
073    /**
074     * @author Eduardo Lundgren
075     * @author Brian Wing Shun Chan
076     * @author Eduardo Garcia
077     * @author Marcellus Tavares
078     */
079    @DoPrivileged
080    public class DDMImpl implements DDM {
081    
082            public static final String FIELDS_DISPLAY_NAME = "_fieldsDisplay";
083    
084            public static final String INSTANCE_SEPARATOR = "_INSTANCE_";
085    
086            public static final String TYPE_CHECKBOX = "checkbox";
087    
088            public static final String TYPE_DDM_DATE = "ddm-date";
089    
090            public static final String TYPE_DDM_DOCUMENTLIBRARY = "ddm-documentlibrary";
091    
092            public static final String TYPE_DDM_LINK_TO_PAGE = "ddm-link-to-page";
093    
094            public static final String TYPE_RADIO = "radio";
095    
096            public static final String TYPE_SELECT = "select";
097    
098            @Override
099            public DDMDisplay getDDMDisplay(ServiceContext serviceContext) {
100                    String refererPortletName = (String)serviceContext.getAttribute(
101                            "refererPortletName");
102    
103                    if (refererPortletName == null) {
104                            refererPortletName = serviceContext.getPortletId();
105                    }
106    
107                    return DDMDisplayRegistryUtil.getDDMDisplay(refererPortletName);
108            }
109    
110            @Override
111            public Serializable getDisplayFieldValue(
112                            ThemeDisplay themeDisplay, Serializable fieldValue, String type)
113                    throws Exception {
114    
115                    if (fieldValue instanceof Date) {
116                            Date valueDate = (Date)fieldValue;
117    
118                            DateFormat dateFormat = DateFormatFactoryUtil.getDate(
119                                    themeDisplay.getLocale());
120    
121                            fieldValue = dateFormat.format(valueDate);
122                    }
123                    else if (type.equals(DDMImpl.TYPE_CHECKBOX)) {
124                            Boolean valueBoolean = (Boolean)fieldValue;
125    
126                            if (valueBoolean) {
127                                    fieldValue = LanguageUtil.get(themeDisplay.getLocale(), "yes");
128                            }
129                            else {
130                                    fieldValue = LanguageUtil.get(themeDisplay.getLocale(), "no");
131                            }
132                    }
133                    else if (type.equals(DDMImpl.TYPE_DDM_DOCUMENTLIBRARY)) {
134                            if (Validator.isNull(fieldValue)) {
135                                    return StringPool.BLANK;
136                            }
137    
138                            String valueString = String.valueOf(fieldValue);
139    
140                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
141                                    valueString);
142    
143                            String uuid = jsonObject.getString("uuid");
144                            long groupId = jsonObject.getLong("groupId");
145    
146                            FileEntry fileEntry =
147                                    DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
148                                            uuid, groupId);
149    
150                            fieldValue = DLUtil.getPreviewURL(
151                                    fileEntry, fileEntry.getFileVersion(), null, StringPool.BLANK,
152                                    false, true);
153                    }
154                    else if (type.equals(DDMImpl.TYPE_DDM_LINK_TO_PAGE)) {
155                            if (Validator.isNull(fieldValue)) {
156                                    return StringPool.BLANK;
157                            }
158    
159                            String valueString = String.valueOf(fieldValue);
160    
161                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
162                                    valueString);
163    
164                            long groupId = jsonObject.getLong("groupId");
165                            boolean privateLayout = jsonObject.getBoolean("privateLayout");
166                            long layoutId = jsonObject.getLong("layoutId");
167    
168                            Layout layout = LayoutLocalServiceUtil.getLayout(
169                                    groupId, privateLayout, layoutId);
170    
171                            fieldValue = PortalUtil.getLayoutFriendlyURL(layout, themeDisplay);
172                    }
173                    else if (type.equals(DDMImpl.TYPE_RADIO) ||
174                                     type.equals(DDMImpl.TYPE_SELECT)) {
175    
176                            String valueString = String.valueOf(fieldValue);
177    
178                            JSONArray jsonArray = JSONFactoryUtil.createJSONArray(valueString);
179    
180                            String[] stringArray = ArrayUtil.toStringArray(jsonArray);
181    
182                            fieldValue = stringArray[0];
183                    }
184    
185                    return fieldValue;
186            }
187    
188            @Override
189            public Fields getFields(
190                            long ddmStructureId, long ddmTemplateId,
191                            ServiceContext serviceContext)
192                    throws PortalException, SystemException {
193    
194                    return getFields(
195                            ddmStructureId, ddmTemplateId, StringPool.BLANK, serviceContext);
196            }
197    
198            @Override
199            public Fields getFields(
200                            long ddmStructureId, long ddmTemplateId, String fieldNamespace,
201                            ServiceContext serviceContext)
202                    throws PortalException, SystemException {
203    
204                    DDMStructure ddmStructure = getDDMStructure(
205                            ddmStructureId, ddmTemplateId);
206    
207                    Set<String> fieldNames = ddmStructure.getFieldNames();
208    
209                    Fields fields = new Fields();
210    
211                    for (String fieldName : fieldNames) {
212                            List<Serializable> fieldValues = getFieldValues(
213                                    ddmStructure, fieldName, fieldNamespace, serviceContext);
214    
215                            if ((fieldValues == null) || fieldValues.isEmpty()) {
216                                    continue;
217                            }
218    
219                            Field field = createField(
220                                    ddmStructure, fieldName, fieldValues, serviceContext);
221    
222                            fields.put(field);
223                    }
224    
225                    return fields;
226            }
227    
228            @Override
229            public Fields getFields(long ddmStructureId, ServiceContext serviceContext)
230                    throws PortalException, SystemException {
231    
232                    return getFields(ddmStructureId, 0, serviceContext);
233            }
234    
235            @Override
236            public Fields getFields(
237                            long ddmStructureId, String fieldNamespace,
238                            ServiceContext serviceContext)
239                    throws PortalException, SystemException {
240    
241                    return getFields(ddmStructureId, 0, fieldNamespace, serviceContext);
242            }
243    
244            @Override
245            public String[] getFieldsDisplayValues(Field fieldsDisplayField)
246                    throws Exception {
247    
248                    DDMStructure ddmStructure = fieldsDisplayField.getDDMStructure();
249    
250                    List<String> fieldsDisplayValues = new ArrayList<String>();
251    
252                    String[] values = StringUtil.split(
253                            (String)fieldsDisplayField.getValue());
254    
255                    for (String value : values) {
256                            String fieldName = StringUtil.extractFirst(
257                                    value, DDMImpl.INSTANCE_SEPARATOR);
258    
259                            if (ddmStructure.hasField(fieldName)) {
260                                    fieldsDisplayValues.add(fieldName);
261                            }
262                    }
263    
264                    return fieldsDisplayValues.toArray(
265                            new String[fieldsDisplayValues.size()]);
266            }
267    
268            @Override
269            public Serializable getIndexedFieldValue(
270                            Serializable fieldValue, String type)
271                    throws Exception {
272    
273                    if (fieldValue instanceof Date) {
274                            Date valueDate = (Date)fieldValue;
275    
276                            DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
277                                    "yyyyMMddHHmmss");
278    
279                            fieldValue = dateFormat.format(valueDate);
280                    }
281                    else if (type.equals(DDMImpl.TYPE_RADIO) ||
282                                     type.equals(DDMImpl.TYPE_SELECT)) {
283    
284                            String valueString = (String)fieldValue;
285    
286                            JSONArray jsonArray = JSONFactoryUtil.createJSONArray(valueString);
287    
288                            String[] stringArray = ArrayUtil.toStringArray(jsonArray);
289    
290                            fieldValue = stringArray[0];
291                    }
292    
293                    return fieldValue;
294            }
295    
296            @Override
297            public OrderByComparator getStructureOrderByComparator(
298                    String orderByCol, String orderByType) {
299    
300                    boolean orderByAsc = false;
301    
302                    if (orderByType.equals("asc")) {
303                            orderByAsc = true;
304                    }
305    
306                    OrderByComparator orderByComparator = null;
307    
308                    if (orderByCol.equals("id")) {
309                            orderByComparator = new StructureIdComparator(orderByAsc);
310                    }
311                    else if (orderByCol.equals("modified-date")) {
312                            orderByComparator = new StructureModifiedDateComparator(orderByAsc);
313                    }
314    
315                    return orderByComparator;
316            }
317    
318            @Override
319            public OrderByComparator getTemplateOrderByComparator(
320                    String orderByCol, String orderByType) {
321    
322                    boolean orderByAsc = false;
323    
324                    if (orderByType.equals("asc")) {
325                            orderByAsc = true;
326                    }
327    
328                    OrderByComparator orderByComparator = null;
329    
330                    if (orderByCol.equals("id")) {
331                            orderByComparator = new TemplateIdComparator(orderByAsc);
332                    }
333                    else if (orderByCol.equals("modified-date")) {
334                            orderByComparator = new TemplateModifiedDateComparator(orderByAsc);
335                    }
336    
337                    return orderByComparator;
338            }
339    
340            @Override
341            public Fields mergeFields(Fields newFields, Fields existingFields) {
342                    Iterator<Field> itr = newFields.iterator(true);
343    
344                    while (itr.hasNext()) {
345                            Field newField = itr.next();
346    
347                            Field existingField = existingFields.get(newField.getName());
348    
349                            if (existingField == null) {
350                                    existingFields.put(newField);
351                            }
352                            else {
353                                    for (Locale locale : newField.getAvailableLocales()) {
354                                            existingField.setValues(locale, newField.getValues(locale));
355                                    }
356    
357                                    existingField.setDefaultLocale(newField.getDefaultLocale());
358                            }
359                    }
360    
361                    return existingFields;
362            }
363    
364            protected Field createField(
365                            DDMStructure ddmStructure, String fieldName,
366                            List<Serializable> fieldValues, ServiceContext serviceContext)
367                    throws PortalException, SystemException {
368    
369                    Field field = new Field();
370    
371                    field.setDDMStructureId(ddmStructure.getStructureId());
372    
373                    String languageId = GetterUtil.getString(
374                            serviceContext.getAttribute("languageId"),
375                            serviceContext.getLanguageId());
376    
377                    Locale locale = LocaleUtil.fromLanguageId(languageId);
378    
379                    String defaultLanguageId = GetterUtil.getString(
380                            serviceContext.getAttribute("defaultLanguageId"));
381    
382                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
383    
384                    if (ddmStructure.isFieldPrivate(fieldName)) {
385                            locale = LocaleUtil.getSiteDefault();
386    
387                            defaultLocale = LocaleUtil.getSiteDefault();
388                    }
389    
390                    field.setDefaultLocale(defaultLocale);
391    
392                    field.setName(fieldName);
393                    field.setValues(locale, fieldValues);
394    
395                    return field;
396            }
397    
398            protected DDMStructure getDDMStructure(
399                            long ddmStructureId, long ddmTemplateId)
400                    throws PortalException, SystemException {
401    
402                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
403                            ddmStructureId);
404    
405                    try {
406                            DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
407                                    ddmTemplateId);
408    
409                            // Clone ddmStructure to make sure changes are never persisted
410    
411                            ddmStructure = (DDMStructure)ddmStructure.clone();
412    
413                            ddmStructure.setXsd(ddmTemplate.getScript());
414                    }
415                    catch (NoSuchTemplateException nste) {
416                    }
417    
418                    return ddmStructure;
419            }
420    
421            protected List<String> getFieldNames(
422                    String fieldNamespace, String fieldName,
423                    ServiceContext serviceContext) {
424    
425                    String[] fieldsDisplayValues = StringUtil.split(
426                            (String)serviceContext.getAttribute(
427                                    fieldNamespace + FIELDS_DISPLAY_NAME));
428    
429                    List<String> privateFieldNames = ListUtil.fromArray(
430                            PropsValues.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_NAMES);
431    
432                    List<String> fieldNames = new ArrayList<String>();
433    
434                    if ((fieldsDisplayValues.length == 0) ||
435                            privateFieldNames.contains(fieldName)) {
436    
437                            fieldNames.add(fieldNamespace + fieldName);
438                    }
439                    else {
440                            for (String namespacedFieldName : fieldsDisplayValues) {
441                                    String fieldNameValue = StringUtil.extractFirst(
442                                            namespacedFieldName, INSTANCE_SEPARATOR);
443    
444                                    if (fieldNameValue.equals(fieldName)) {
445                                            fieldNames.add(fieldNamespace + namespacedFieldName);
446                                    }
447                            }
448                    }
449    
450                    return fieldNames;
451            }
452    
453            protected List<Serializable> getFieldValues(
454                            DDMStructure ddmStructure, String fieldName, String fieldNamespace,
455                            ServiceContext serviceContext)
456                    throws PortalException, SystemException {
457    
458                    String fieldDataType = ddmStructure.getFieldDataType(fieldName);
459                    String fieldType = ddmStructure.getFieldType(fieldName);
460    
461                    List<String> fieldNames = getFieldNames(
462                            fieldNamespace, fieldName, serviceContext);
463    
464                    List<Serializable> fieldValues = new ArrayList<Serializable>(
465                            fieldNames.size());
466    
467                    for (String fieldNameValue : fieldNames) {
468                            Serializable fieldValue = serviceContext.getAttribute(
469                                    fieldNameValue);
470    
471                            if (fieldDataType.equals(FieldConstants.DATE)) {
472                                    int fieldValueMonth = GetterUtil.getInteger(
473                                            serviceContext.getAttribute(fieldNameValue + "Month"));
474                                    int fieldValueDay = GetterUtil.getInteger(
475                                            serviceContext.getAttribute(fieldNameValue + "Day"));
476                                    int fieldValueYear = GetterUtil.getInteger(
477                                            serviceContext.getAttribute(fieldNameValue + "Year"));
478    
479                                    Date fieldValueDate = PortalUtil.getDate(
480                                            fieldValueMonth, fieldValueDay, fieldValueYear);
481    
482                                    if (fieldValueDate != null) {
483                                            fieldValue = String.valueOf(fieldValueDate.getTime());
484                                    }
485                            }
486                            else if (fieldDataType.equals(FieldConstants.IMAGE) &&
487                                             Validator.isNull(fieldValue)) {
488    
489                                    HttpServletRequest request = serviceContext.getRequest();
490    
491                                    if (!(request instanceof UploadRequest)) {
492                                            return null;
493                                    }
494    
495                                    UploadRequest uploadRequest = (UploadRequest)request;
496    
497                                    File file = uploadRequest.getFile(fieldNameValue);
498    
499                                    try {
500                                            byte[] bytes = FileUtil.getBytes(file);
501    
502                                            if (ArrayUtil.isNotEmpty(bytes)) {
503                                                    fieldValue = UnicodeFormatter.bytesToHex(bytes);
504                                            }
505                                            else {
506                                                    fieldValue = "update";
507                                            }
508                                    }
509                                    catch (IOException ioe) {
510                                            return null;
511                                    }
512                            }
513    
514                            if (fieldValue == null) {
515                                    return null;
516                            }
517    
518                            if (DDMImpl.TYPE_RADIO.equals(fieldType) ||
519                                    DDMImpl.TYPE_SELECT.equals(fieldType)) {
520    
521                                    if (fieldValue instanceof String) {
522                                            fieldValue = new String[] {String.valueOf(fieldValue)};
523                                    }
524    
525                                    fieldValue = JSONFactoryUtil.serialize(fieldValue);
526                            }
527    
528                            Serializable fieldValueSerializable =
529                                    FieldConstants.getSerializable(
530                                            fieldDataType, GetterUtil.getString(fieldValue));
531    
532                            fieldValues.add(fieldValueSerializable);
533                    }
534    
535                    return fieldValues;
536            }
537    
538    }