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.dynamicdatalists.util;
016    
017    import com.liferay.portal.kernel.json.JSONArray;
018    import com.liferay.portal.kernel.json.JSONFactoryUtil;
019    import com.liferay.portal.kernel.json.JSONObject;
020    import com.liferay.portal.kernel.language.LanguageUtil;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.repository.model.FileEntry;
024    import com.liferay.portal.kernel.search.Hits;
025    import com.liferay.portal.kernel.search.Indexer;
026    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
027    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028    import com.liferay.portal.kernel.template.TemplateConstants;
029    import com.liferay.portal.kernel.util.Constants;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.LocaleThreadLocal;
032    import com.liferay.portal.kernel.util.LocaleUtil;
033    import com.liferay.portal.kernel.util.ParamUtil;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.StringPool;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Group;
038    import com.liferay.portal.model.PortletConstants;
039    import com.liferay.portal.service.GroupLocalServiceUtil;
040    import com.liferay.portal.service.LayoutServiceUtil;
041    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
042    import com.liferay.portal.service.ServiceContext;
043    import com.liferay.portal.templateparser.Transformer;
044    import com.liferay.portal.theme.ThemeDisplay;
045    import com.liferay.portal.util.PortletKeys;
046    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
047    import com.liferay.portlet.dynamicdatalists.NoSuchRecordException;
048    import com.liferay.portlet.dynamicdatalists.model.DDLRecord;
049    import com.liferay.portlet.dynamicdatalists.model.DDLRecordConstants;
050    import com.liferay.portlet.dynamicdatalists.model.DDLRecordSet;
051    import com.liferay.portlet.dynamicdatalists.model.DDLRecordVersion;
052    import com.liferay.portlet.dynamicdatalists.service.DDLRecordLocalServiceUtil;
053    import com.liferay.portlet.dynamicdatalists.service.DDLRecordServiceUtil;
054    import com.liferay.portlet.dynamicdatalists.service.DDLRecordSetLocalServiceUtil;
055    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
056    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
057    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
058    import com.liferay.portlet.dynamicdatamapping.storage.Field;
059    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
060    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
061    import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
062    import com.liferay.portlet.dynamicdatamapping.util.DDMImpl;
063    import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
064    
065    import java.util.ArrayList;
066    import java.util.Date;
067    import java.util.HashMap;
068    import java.util.List;
069    import java.util.Locale;
070    import java.util.Map;
071    
072    import javax.portlet.PortletPreferences;
073    import javax.portlet.RenderRequest;
074    import javax.portlet.RenderResponse;
075    
076    import javax.servlet.http.HttpServletRequest;
077    
078    /**
079     * @author Marcellus Tavares
080     * @author Eduardo Lundgren
081     */
082    @DoPrivileged
083    public class DDLImpl implements DDL {
084    
085            @Override
086            public JSONObject getRecordJSONObject(DDLRecord record) throws Exception {
087                    return getRecordJSONObject(record, false);
088            }
089    
090            @Override
091            public JSONObject getRecordJSONObject(
092                            DDLRecord record, boolean latestRecordVersion)
093                    throws Exception {
094    
095                    DDLRecordSet recordSet = record.getRecordSet();
096    
097                    DDMStructure ddmStructure = recordSet.getDDMStructure();
098    
099                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
100    
101                    for (String fieldName : ddmStructure.getFieldNames()) {
102                            jsonObject.put(fieldName, StringPool.BLANK);
103                    }
104    
105                    jsonObject.put("displayIndex", record.getDisplayIndex());
106                    jsonObject.put("recordId", record.getRecordId());
107    
108                    DDLRecordVersion recordVersion = record.getRecordVersion();
109    
110                    if (latestRecordVersion) {
111                            recordVersion = record.getLatestRecordVersion();
112                    }
113    
114                    Fields fields = StorageEngineUtil.getFields(
115                            recordVersion.getDDMStorageId());
116    
117                    for (Field field : fields) {
118                            String fieldName = field.getName();
119                            String fieldType = field.getType();
120                            Object fieldValue = field.getValue();
121    
122                            if (fieldValue instanceof Date) {
123                                    jsonObject.put(fieldName, ((Date)fieldValue).getTime());
124                            }
125                            else if (fieldType.equals(DDMImpl.TYPE_DDM_DOCUMENTLIBRARY) &&
126                                             Validator.isNotNull(fieldValue)) {
127    
128                                    JSONObject fieldValueJSONObject =
129                                            JSONFactoryUtil.createJSONObject(
130                                                    String.valueOf(fieldValue));
131    
132                                    String uuid = fieldValueJSONObject.getString("uuid");
133                                    long groupId = fieldValueJSONObject.getLong("groupId");
134    
135                                    fieldValueJSONObject.put(
136                                            "title", getFileEntryTitle(uuid, groupId));
137    
138                                    jsonObject.put(fieldName, fieldValueJSONObject.toString());
139                            }
140                            else if (fieldType.equals(DDMImpl.TYPE_DDM_LINK_TO_PAGE) &&
141                                             Validator.isNotNull(fieldValue)) {
142    
143                                    JSONObject fieldValueJSONObject =
144                                            JSONFactoryUtil.createJSONObject(
145                                                    String.valueOf(fieldValue));
146    
147                                    long groupId = fieldValueJSONObject.getLong("groupId");
148                                    boolean privateLayout = fieldValueJSONObject.getBoolean(
149                                            "privateLayout");
150                                    long layoutId = fieldValueJSONObject.getLong("layoutId");
151                                    Locale locale = LocaleThreadLocal.getThemeDisplayLocale();
152    
153                                    String layoutName = getLayoutName(
154                                            groupId, privateLayout, layoutId,
155                                            LanguageUtil.getLanguageId(locale));
156    
157                                    fieldValueJSONObject.put("name", layoutName);
158    
159                                    jsonObject.put(fieldName, fieldValueJSONObject.toString());
160                            }
161                            else if ((fieldType.equals(DDMImpl.TYPE_RADIO) ||
162                                              fieldType.equals(DDMImpl.TYPE_SELECT)) &&
163                                             Validator.isNotNull(fieldValue)) {
164    
165                                    fieldValue = JSONFactoryUtil.createJSONArray(
166                                            String.valueOf(fieldValue));
167    
168                                    jsonObject.put(fieldName, (JSONArray)fieldValue);
169                            }
170                            else {
171                                    jsonObject.put(fieldName, String.valueOf(fieldValue));
172                            }
173                    }
174    
175                    return jsonObject;
176            }
177    
178            @Override
179            public List<DDLRecord> getRecords(Hits hits) throws Exception {
180                    List<DDLRecord> records = new ArrayList<DDLRecord>();
181    
182                    List<com.liferay.portal.kernel.search.Document> documents =
183                            hits.toList();
184    
185                    for (com.liferay.portal.kernel.search.Document document : documents) {
186                            long recordId = GetterUtil.getLong(
187                                    document.get(
188                                            com.liferay.portal.kernel.search.Field.ENTRY_CLASS_PK));
189    
190                            try {
191                                    DDLRecord record = DDLRecordLocalServiceUtil.getRecord(
192                                            recordId);
193    
194                                    records.add(record);
195                            }
196                            catch (NoSuchRecordException nsre) {
197                                    if (_log.isWarnEnabled()) {
198                                            _log.warn(
199                                                    "DDL record index is stale and contains record " +
200                                                            recordId);
201                                    }
202    
203                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
204                                            DDLRecord.class);
205    
206                                    long companyId = GetterUtil.getLong(
207                                            document.get(
208                                                    com.liferay.portal.kernel.search.Field.COMPANY_ID));
209    
210                                    indexer.delete(companyId, document.getUID());
211                            }
212                    }
213    
214                    return records;
215            }
216    
217            @Override
218            public JSONArray getRecordSetJSONArray(DDLRecordSet recordSet)
219                    throws Exception {
220    
221                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
222    
223                    DDMStructure ddmStructure = recordSet.getDDMStructure();
224    
225                    Map<String, Map<String, String>> fieldsMap =
226                            ddmStructure.getFieldsMap();
227    
228                    for (Map<String, String> fields : fieldsMap.values()) {
229                            String name = fields.get(FieldConstants.NAME);
230    
231                            if (ddmStructure.isFieldPrivate(name)) {
232                                    continue;
233                            }
234    
235                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
236    
237                            String dataType = fields.get(FieldConstants.DATA_TYPE);
238    
239                            jsonObject.put("dataType", dataType);
240    
241                            boolean editable = GetterUtil.getBoolean(
242                                    fields.get(FieldConstants.EDITABLE), true);
243    
244                            jsonObject.put("editable", editable);
245    
246                            String label = fields.get(FieldConstants.LABEL);
247    
248                            jsonObject.put("label", label);
249    
250                            jsonObject.put("name", name);
251    
252                            boolean required = GetterUtil.getBoolean(
253                                    fields.get(FieldConstants.REQUIRED));
254    
255                            jsonObject.put("required", required);
256    
257                            boolean sortable = GetterUtil.getBoolean(
258                                    fields.get(FieldConstants.SORTABLE), true);
259    
260                            jsonObject.put("sortable", sortable);
261    
262                            String type = fields.get(FieldConstants.TYPE);
263    
264                            jsonObject.put("type", type);
265    
266                            jsonArray.put(jsonObject);
267                    }
268    
269                    return jsonArray;
270            }
271    
272            @Override
273            public JSONArray getRecordsJSONArray(DDLRecordSet recordSet)
274                    throws Exception {
275    
276                    return getRecordsJSONArray(recordSet.getRecords(), false);
277            }
278    
279            @Override
280            public JSONArray getRecordsJSONArray(List<DDLRecord> records)
281                    throws Exception {
282    
283                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
284    
285                    for (DDLRecord record : records) {
286                            JSONObject jsonObject = getRecordJSONObject(record);
287    
288                            jsonArray.put(jsonObject);
289                    }
290    
291                    return jsonArray;
292            }
293    
294            @Override
295            public JSONArray getRecordsJSONArray(
296                            List<DDLRecord> records, boolean latestRecordVersion)
297                    throws Exception {
298    
299                    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
300    
301                    for (DDLRecord record : records) {
302                            JSONObject jsonObject = getRecordJSONObject(
303                                    record, latestRecordVersion);
304    
305                            jsonArray.put(jsonObject);
306                    }
307    
308                    return jsonArray;
309            }
310    
311            @Override
312            public String getTemplateContent(
313                            long ddmTemplateId, DDLRecordSet recordSet,
314                            ThemeDisplay themeDisplay, RenderRequest renderRequest,
315                            RenderResponse renderResponse)
316                    throws Exception {
317    
318                    Map<String, Object> contextObjects = new HashMap<String, Object>();
319    
320                    contextObjects.put(
321                            DDLConstants.RESERVED_DDM_STRUCTURE_ID,
322                            recordSet.getDDMStructureId());
323                    contextObjects.put(
324                            DDLConstants.RESERVED_DDM_TEMPLATE_ID, ddmTemplateId);
325                    contextObjects.put(
326                            DDLConstants.RESERVED_RECORD_SET_DESCRIPTION,
327                            recordSet.getDescription(themeDisplay.getLocale()));
328                    contextObjects.put(
329                            DDLConstants.RESERVED_RECORD_SET_ID, recordSet.getRecordSetId());
330                    contextObjects.put(
331                            DDLConstants.RESERVED_RECORD_SET_NAME,
332                            recordSet.getName(themeDisplay.getLocale()));
333                    contextObjects.put(TemplateConstants.TEMPLATE_ID, ddmTemplateId);
334    
335                    String viewMode = ParamUtil.getString(renderRequest, "viewMode");
336    
337                    if (Validator.isNull(viewMode)) {
338                            viewMode = Constants.VIEW;
339                    }
340    
341                    contextObjects.put("viewMode", viewMode);
342    
343                    DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
344                            ddmTemplateId);
345    
346                    contextObjects.put(
347                            TemplateConstants.CLASS_NAME_ID, ddmTemplate.getClassNameId());
348    
349                    return _transformer.transform(
350                            themeDisplay, contextObjects, ddmTemplate.getScript(),
351                            ddmTemplate.getLanguage());
352            }
353    
354            @Override
355            public boolean isEditable(
356                            HttpServletRequest request, String portletId, long groupId)
357                    throws Exception {
358    
359                    boolean defaultValue = ParamUtil.getBoolean(request, "editable", true);
360    
361                    return isEditable(portletId, groupId, defaultValue);
362            }
363    
364            @Override
365            public boolean isEditable(
366                            PortletPreferences preferences, String portletId, long groupId)
367                    throws Exception {
368    
369                    boolean defaultValue = GetterUtil.getBoolean(
370                            preferences.getValue("editable", null), true);
371    
372                    return isEditable(portletId, groupId, defaultValue);
373            }
374    
375            @Override
376            public DDLRecord updateRecord(
377                            long recordId, long recordSetId, boolean mergeFields,
378                            boolean checkPermission, ServiceContext serviceContext)
379                    throws Exception {
380    
381                    DDLRecord record = DDLRecordLocalServiceUtil.fetchRecord(recordId);
382    
383                    PortletPreferences preferences =
384                            PortletPreferencesLocalServiceUtil.getPreferences(
385                                    serviceContext.getPortletPreferencesIds());
386    
387                    if (!isEditable(
388                                    preferences, serviceContext.getPortletId(),
389                                    serviceContext.getScopeGroupId())) {
390    
391                            return record;
392                    }
393    
394                    boolean majorVersion = ParamUtil.getBoolean(
395                            serviceContext, "majorVersion");
396    
397                    DDLRecordSet recordSet = DDLRecordSetLocalServiceUtil.getDDLRecordSet(
398                            recordSetId);
399    
400                    DDMStructure ddmStructure = recordSet.getDDMStructure();
401    
402                    Fields fields = DDMUtil.getFields(
403                            ddmStructure.getStructureId(), serviceContext);
404    
405                    if (record != null) {
406                            if (checkPermission) {
407                                    record = DDLRecordServiceUtil.updateRecord(
408                                            recordId, majorVersion,
409                                            DDLRecordConstants.DISPLAY_INDEX_DEFAULT, fields,
410                                            mergeFields, serviceContext);
411                            }
412                            else {
413                                    record = DDLRecordLocalServiceUtil.updateRecord(
414                                            serviceContext.getUserId(), recordId, majorVersion,
415                                            DDLRecordConstants.DISPLAY_INDEX_DEFAULT, fields,
416                                            mergeFields, serviceContext);
417                            }
418                    }
419                    else {
420                            if (checkPermission) {
421                                    record = DDLRecordServiceUtil.addRecord(
422                                            serviceContext.getScopeGroupId(), recordSetId,
423                                            DDLRecordConstants.DISPLAY_INDEX_DEFAULT, fields,
424                                            serviceContext);
425                            }
426                            else {
427                                    record = DDLRecordLocalServiceUtil.addRecord(
428                                            serviceContext.getUserId(),
429                                            serviceContext.getScopeGroupId(), recordSetId,
430                                            DDLRecordConstants.DISPLAY_INDEX_DEFAULT, fields,
431                                            serviceContext);
432                            }
433                    }
434    
435                    return record;
436            }
437    
438            @Override
439            public DDLRecord updateRecord(
440                            long recordId, long recordSetId, boolean mergeFields,
441                            ServiceContext serviceContext)
442                    throws Exception {
443    
444                    return updateRecord(
445                            recordId, recordSetId, mergeFields, true, serviceContext);
446            }
447    
448            protected String getFileEntryTitle(String uuid, long groupId) {
449                    try {
450                            FileEntry fileEntry =
451                                    DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
452                                            uuid, groupId);
453    
454                            return fileEntry.getTitle();
455                    }
456                    catch (Exception e) {
457                            return LanguageUtil.format(
458                                    LocaleUtil.getSiteDefault(), "is-temporarily-unavailable",
459                                    "content");
460                    }
461            }
462    
463            protected String getLayoutName(
464                    long groupId, boolean privateLayout, long layoutId, String languageId) {
465    
466                    try {
467                            return LayoutServiceUtil.getLayoutName(
468                                    groupId, privateLayout, layoutId, languageId);
469                    }
470                    catch (Exception e) {
471                            return LanguageUtil.format(
472                                    LocaleUtil.getSiteDefault(), "is-temporarily-unavailable",
473                                    "content");
474                    }
475            }
476    
477            protected boolean isEditable(
478                            String portletId, long groupId, boolean defaultValue)
479                    throws Exception {
480    
481                    String rootPortletId = PortletConstants.getRootPortletId(portletId);
482    
483                    if (rootPortletId.equals(PortletKeys.DYNAMIC_DATA_LISTS)) {
484                            return true;
485                    }
486    
487                    Group group = GroupLocalServiceUtil.fetchGroup(groupId);
488    
489                    if ((group == null) || group.isInStagingPortlet(portletId)) {
490                            return false;
491                    }
492    
493                    return defaultValue;
494            }
495    
496            private static Log _log = LogFactoryUtil.getLog(DDLImpl.class);
497    
498            private Transformer _transformer = new Transformer(
499                    PropsKeys.DYNAMIC_DATA_LISTS_ERROR_TEMPLATE, true);
500    
501    }