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    
362                    return existingFields;
363            }
364    
365            protected Field createField(
366                            DDMStructure ddmStructure, String fieldName,
367                            List<Serializable> fieldValues, ServiceContext serviceContext)
368                    throws PortalException, SystemException {
369    
370                    Field field = new Field();
371    
372                    field.setDDMStructureId(ddmStructure.getStructureId());
373    
374                    String languageId = GetterUtil.getString(
375                            serviceContext.getAttribute("languageId"),
376                            serviceContext.getLanguageId());
377    
378                    Locale locale = LocaleUtil.fromLanguageId(languageId);
379    
380                    String defaultLanguageId = GetterUtil.getString(
381                            serviceContext.getAttribute("defaultLanguageId"));
382    
383                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
384    
385                    if (ddmStructure.isFieldPrivate(fieldName)) {
386                            locale = LocaleUtil.getSiteDefault();
387    
388                            defaultLocale = LocaleUtil.getSiteDefault();
389                    }
390    
391                    field.setDefaultLocale(defaultLocale);
392    
393                    field.setName(fieldName);
394                    field.setValues(locale, fieldValues);
395    
396                    return field;
397            }
398    
399            protected DDMStructure getDDMStructure(
400                            long ddmStructureId, long ddmTemplateId)
401                    throws PortalException, SystemException {
402    
403                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
404                            ddmStructureId);
405    
406                    try {
407                            DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
408                                    ddmTemplateId);
409    
410                            // Clone ddmStructure to make sure changes are never persisted
411    
412                            ddmStructure = (DDMStructure)ddmStructure.clone();
413    
414                            ddmStructure.setXsd(ddmTemplate.getScript());
415                    }
416                    catch (NoSuchTemplateException nste) {
417                    }
418    
419                    return ddmStructure;
420            }
421    
422            protected List<String> getFieldNames(
423                    String fieldNamespace, String fieldName,
424                    ServiceContext serviceContext) {
425    
426                    String[] fieldsDisplayValues = StringUtil.split(
427                            (String)serviceContext.getAttribute(
428                                    fieldNamespace + FIELDS_DISPLAY_NAME));
429    
430                    List<String> privateFieldNames = ListUtil.fromArray(
431                            PropsValues.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_NAMES);
432    
433                    List<String> fieldNames = new ArrayList<String>();
434    
435                    if ((fieldsDisplayValues.length == 0) ||
436                            privateFieldNames.contains(fieldName)) {
437    
438                            fieldNames.add(fieldNamespace + fieldName);
439                    }
440                    else {
441                            for (String namespacedFieldName : fieldsDisplayValues) {
442                                    String fieldNameValue = StringUtil.extractFirst(
443                                            namespacedFieldName, INSTANCE_SEPARATOR);
444    
445                                    if (fieldNameValue.equals(fieldName)) {
446                                            fieldNames.add(fieldNamespace + namespacedFieldName);
447                                    }
448                            }
449                    }
450    
451                    return fieldNames;
452            }
453    
454            protected List<Serializable> getFieldValues(
455                            DDMStructure ddmStructure, String fieldName, String fieldNamespace,
456                            ServiceContext serviceContext)
457                    throws PortalException, SystemException {
458    
459                    String fieldDataType = ddmStructure.getFieldDataType(fieldName);
460                    String fieldType = ddmStructure.getFieldType(fieldName);
461    
462                    List<String> fieldNames = getFieldNames(
463                            fieldNamespace, fieldName, serviceContext);
464    
465                    List<Serializable> fieldValues = new ArrayList<Serializable>(
466                            fieldNames.size());
467    
468                    for (String fieldNameValue : fieldNames) {
469                            Serializable fieldValue = serviceContext.getAttribute(
470                                    fieldNameValue);
471    
472                            if (fieldDataType.equals(FieldConstants.DATE)) {
473                                    int fieldValueMonth = GetterUtil.getInteger(
474                                            serviceContext.getAttribute(fieldNameValue + "Month"));
475                                    int fieldValueDay = GetterUtil.getInteger(
476                                            serviceContext.getAttribute(fieldNameValue + "Day"));
477                                    int fieldValueYear = GetterUtil.getInteger(
478                                            serviceContext.getAttribute(fieldNameValue + "Year"));
479    
480                                    Date fieldValueDate = PortalUtil.getDate(
481                                            fieldValueMonth, fieldValueDay, fieldValueYear);
482    
483                                    if (fieldValueDate != null) {
484                                            fieldValue = String.valueOf(fieldValueDate.getTime());
485                                    }
486                            }
487                            else if (fieldDataType.equals(FieldConstants.IMAGE) &&
488                                             Validator.isNull(fieldValue)) {
489    
490                                    HttpServletRequest request = serviceContext.getRequest();
491    
492                                    if (!(request instanceof UploadRequest)) {
493                                            return null;
494                                    }
495    
496                                    UploadRequest uploadRequest = (UploadRequest)request;
497    
498                                    File file = uploadRequest.getFile(fieldNameValue);
499    
500                                    try {
501                                            byte[] bytes = FileUtil.getBytes(file);
502    
503                                            if ((bytes != null) && (bytes.length > 0)) {
504                                                    fieldValue = UnicodeFormatter.bytesToHex(bytes);
505                                            }
506                                            else {
507                                                    fieldValue = "update";
508                                            }
509                                    }
510                                    catch (IOException ioe) {
511                                            return null;
512                                    }
513                            }
514    
515                            if (fieldValue == null) {
516                                    return null;
517                            }
518    
519                            if (DDMImpl.TYPE_RADIO.equals(fieldType) ||
520                                    DDMImpl.TYPE_SELECT.equals(fieldType)) {
521    
522                                    if (fieldValue instanceof String) {
523                                            fieldValue = new String[] {String.valueOf(fieldValue)};
524                                    }
525    
526                                    fieldValue = JSONFactoryUtil.serialize(fieldValue);
527                            }
528    
529                            Serializable fieldValueSerializable =
530                                    FieldConstants.getSerializable(
531                                            fieldDataType, GetterUtil.getString(fieldValue));
532    
533                            fieldValues.add(fieldValueSerializable);
534                    }
535    
536                    return fieldValues;
537            }
538    
539    }