001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.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.servlet.ServletResponseUtil;
023    import com.liferay.portal.kernel.upload.UploadRequest;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.LocaleUtil;
026    import com.liferay.portal.kernel.util.MimeTypesUtil;
027    import com.liferay.portal.kernel.util.OrderByComparator;
028    import com.liferay.portal.kernel.util.StreamUtil;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.WebKeys;
032    import com.liferay.portal.model.BaseModel;
033    import com.liferay.portal.model.CompanyConstants;
034    import com.liferay.portal.service.ServiceContext;
035    import com.liferay.portal.theme.ThemeDisplay;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
038    import com.liferay.portlet.documentlibrary.DuplicateFileException;
039    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
040    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadataModel;
041    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
042    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
043    import com.liferay.portlet.dynamicdatalists.model.DDLRecord;
044    import com.liferay.portlet.dynamicdatalists.model.DDLRecordModel;
045    import com.liferay.portlet.dynamicdatalists.model.DDLRecordVersion;
046    import com.liferay.portlet.dynamicdatamapping.NoSuchTemplateException;
047    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
048    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
049    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
050    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
051    import com.liferay.portlet.dynamicdatamapping.storage.Field;
052    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
053    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
054    import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
055    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureIdComparator;
056    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureModifiedDateComparator;
057    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateIdComparator;
058    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateModifiedDateComparator;
059    
060    import java.io.InputStream;
061    import java.io.Serializable;
062    
063    import java.util.ArrayList;
064    import java.util.Date;
065    import java.util.Iterator;
066    import java.util.List;
067    import java.util.Locale;
068    import java.util.Set;
069    
070    import javax.servlet.http.HttpServletRequest;
071    import javax.servlet.http.HttpServletResponse;
072    
073    /**
074     * @author Eduardo Lundgren
075     * @author Brian Wing Shun Chan
076     * @author Eduardo Garcia
077     * @author Marcellus Tavares
078     */
079    public class DDMImpl implements DDM {
080    
081            public static final String TYPE_CHECKBOX = "checkbox";
082    
083            public static final String TYPE_DDM_DOCUMENTLIBRARY = "ddm-documentlibrary";
084    
085            public static final String TYPE_DDM_FILEUPLOAD = "ddm-fileupload";
086    
087            public static final String TYPE_RADIO = "radio";
088    
089            public static final String TYPE_SELECT = "select";
090    
091            public Fields getFields(
092                            long ddmStructureId, long ddmTemplateId,
093                            ServiceContext serviceContext)
094                    throws PortalException, SystemException {
095    
096                    return getFields(
097                            ddmStructureId, ddmTemplateId, StringPool.BLANK, serviceContext);
098            }
099    
100            public Fields getFields(
101                            long ddmStructureId, long ddmTemplateId, String fieldNamespace,
102                            ServiceContext serviceContext)
103                    throws PortalException, SystemException {
104    
105                    DDMStructure ddmStructure = getDDMStructure(
106                            ddmStructureId, ddmTemplateId);
107    
108                    Set<String> fieldNames = ddmStructure.getFieldNames();
109    
110                    Fields fields = new Fields();
111    
112                    for (String fieldName : fieldNames) {
113                            JSONObject repeatabaleFieldsMapJSONObject =
114                                    getRepeatableFieldsMapJSONObject(serviceContext);
115    
116                            List<Serializable> fieldValues = getFieldValues(
117                                    ddmStructure, repeatabaleFieldsMapJSONObject, fieldName,
118                                    fieldNamespace, serviceContext);
119    
120                            if ((fieldValues == null) || fieldValues.isEmpty()) {
121                                    continue;
122                            }
123    
124                            String languageId = GetterUtil.getString(
125                                    serviceContext.getAttribute("languageId"),
126                                    serviceContext.getLanguageId());
127    
128                            Locale locale = LocaleUtil.fromLanguageId(languageId);
129    
130                            Field field = new Field(
131                                    ddmStructureId, fieldName, fieldValues, locale);
132    
133                            String defaultLanguageId = GetterUtil.getString(
134                                    serviceContext.getAttribute("defaultLanguageId"));
135    
136                            Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
137    
138                            field.setDefaultLocale(defaultLocale);
139    
140                            fields.put(field);
141                    }
142    
143                    return fields;
144            }
145    
146            public Fields getFields(long ddmStructureId, ServiceContext serviceContext)
147                    throws PortalException, SystemException {
148    
149                    return getFields(ddmStructureId, 0, serviceContext);
150            }
151    
152            public Fields getFields(
153                            long ddmStructureId, String fieldNamespace,
154                            ServiceContext serviceContext)
155                    throws PortalException, SystemException {
156    
157                    return getFields(ddmStructureId, 0, fieldNamespace, serviceContext);
158            }
159    
160            public String getFileUploadPath(BaseModel<?> baseModel) {
161                    StringBundler sb = new StringBundler(7);
162    
163                    try {
164                            long primaryKey = 0;
165    
166                            String version = StringPool.BLANK;
167    
168                            if (baseModel instanceof DDLRecordModel) {
169                                    DDLRecord record = (DDLRecord)baseModel;
170    
171                                    primaryKey = record.getPrimaryKey();
172    
173                                    DDLRecordVersion recordVersion =
174                                            record.getLatestRecordVersion();
175    
176                                    version = recordVersion.getVersion();
177                            }
178                            else if (baseModel instanceof DLFileEntryMetadataModel) {
179                                    DLFileEntryMetadata fileEntryMetadata =
180                                            (DLFileEntryMetadata)baseModel;
181    
182                                    primaryKey = fileEntryMetadata.getPrimaryKey();
183    
184                                    DLFileVersion fileVersion = fileEntryMetadata.getFileVersion();
185    
186                                    version = fileVersion.getVersion();
187                            }
188    
189                            sb.append("ddm");
190                            sb.append(StringPool.SLASH);
191                            sb.append(baseModel.getModelClassName());
192                            sb.append(StringPool.SLASH);
193                            sb.append(primaryKey);
194                            sb.append(StringPool.SLASH);
195                            sb.append(version);
196                    }
197                    catch (Exception e) {
198                    }
199    
200                    return sb.toString();
201            }
202    
203            public OrderByComparator getStructureOrderByComparator(
204                    String orderByCol, String orderByType) {
205    
206                    boolean orderByAsc = false;
207    
208                    if (orderByType.equals("asc")) {
209                            orderByAsc = true;
210                    }
211    
212                    OrderByComparator orderByComparator = null;
213    
214                    if (orderByCol.equals("id")) {
215                            orderByComparator = new StructureIdComparator(orderByAsc);
216                    }
217                    else if (orderByCol.equals("modified-date")) {
218                            orderByComparator = new StructureModifiedDateComparator(orderByAsc);
219                    }
220    
221                    return orderByComparator;
222            }
223    
224            public OrderByComparator getTemplateOrderByComparator(
225                    String orderByCol, String orderByType) {
226    
227                    boolean orderByAsc = false;
228    
229                    if (orderByType.equals("asc")) {
230                            orderByAsc = true;
231                    }
232    
233                    OrderByComparator orderByComparator = null;
234    
235                    if (orderByCol.equals("id")) {
236                            orderByComparator = new TemplateIdComparator(orderByAsc);
237                    }
238                    else if (orderByCol.equals("modified-date")) {
239                            orderByComparator = new TemplateModifiedDateComparator(orderByAsc);
240                    }
241    
242                    return orderByComparator;
243            }
244    
245            public Fields mergeFields(Fields newFields, Fields existingFields) {
246                    Iterator<Field> itr = newFields.iterator();
247    
248                    while (itr.hasNext()) {
249                            Field newField = itr.next();
250    
251                            Field existingField = existingFields.get(newField.getName());
252    
253                            if (existingField == null) {
254                                    existingFields.put(newField);
255                            }
256                            else {
257                                    for (Locale locale : newField.getAvailableLocales()) {
258                                            existingField.setValues(locale, newField.getValues(locale));
259                                    }
260    
261                                    existingField.setDefaultLocale(newField.getDefaultLocale());
262                            }
263    
264                    }
265    
266                    return existingFields;
267            }
268    
269            public void sendFieldFile(
270                            HttpServletRequest request, HttpServletResponse response,
271                            Field field, int valueIndex)
272                    throws Exception {
273    
274                    if (field == null) {
275                            return;
276                    }
277    
278                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
279                            WebKeys.THEME_DISPLAY);
280    
281                    DDMStructure structure = field.getDDMStructure();
282    
283                    Serializable fieldValue = field.getValue(
284                            themeDisplay.getLocale(), valueIndex);
285    
286                    JSONObject fileJSONObject = JSONFactoryUtil.createJSONObject(
287                            String.valueOf(fieldValue));
288    
289                    String fileName = fileJSONObject.getString("name");
290                    String filePath = fileJSONObject.getString("path");
291    
292                    InputStream is = DLStoreUtil.getFileAsStream(
293                            structure.getCompanyId(), CompanyConstants.SYSTEM, filePath);
294                    long contentLength = DLStoreUtil.getFileSize(
295                            structure.getCompanyId(), CompanyConstants.SYSTEM, filePath);
296                    String contentType = MimeTypesUtil.getContentType(fileName);
297    
298                    ServletResponseUtil.sendFile(
299                            request, response, fileName, is, contentLength, contentType);
300            }
301    
302            public void uploadFieldFile(
303                            long structureId, long storageId, BaseModel<?> baseModel,
304                            String fieldName, ServiceContext serviceContext)
305                    throws Exception {
306    
307                    uploadFieldFile(
308                            structureId, storageId, baseModel, fieldName, StringPool.BLANK,
309                            serviceContext);
310            }
311    
312            public void uploadFieldFile(
313                            long structureId, long storageId, BaseModel<?> baseModel,
314                            String fieldName, String fieldNamespace,
315                            ServiceContext serviceContext)
316                    throws Exception {
317    
318                    HttpServletRequest request = serviceContext.getRequest();
319    
320                    if (!(request instanceof UploadRequest)) {
321                            return;
322                    }
323    
324                    UploadRequest uploadRequest = (UploadRequest)request;
325    
326                    Fields fields = StorageEngineUtil.getFields(storageId);
327    
328                    List<String> fieldNames = getFieldNames(
329                            structureId, fieldNamespace, fieldName, serviceContext);
330    
331                    List<Serializable> fieldValues = new ArrayList<Serializable>(
332                            fieldNames.size());
333    
334                    for (String fieldNameValue : fieldNames) {
335                            InputStream inputStream = null;
336    
337                            try {
338                                    String fileName = uploadRequest.getFileName(fieldNameValue);
339    
340                                    inputStream = uploadRequest.getFileAsStream(fieldName, true);
341    
342                                    if (inputStream != null) {
343                                            String filePath = storeFieldFile(
344                                                    baseModel, fieldName, inputStream, serviceContext);
345    
346                                            JSONObject recordFileJSONObject =
347                                                    JSONFactoryUtil.createJSONObject();
348    
349                                            recordFileJSONObject.put("name", fileName);
350                                            recordFileJSONObject.put("path", filePath);
351                                            recordFileJSONObject.put(
352                                                    "className", baseModel.getModelClassName());
353                                            recordFileJSONObject.put(
354                                                    "classPK",
355                                                    String.valueOf(baseModel.getPrimaryKeyObj()));
356    
357                                            String fieldValue = recordFileJSONObject.toString();
358    
359                                            fieldValues.add(fieldValue);
360                                    }
361                                    else if (fields.contains(fieldName)) {
362                                            continue;
363                                    }
364                            }
365                            finally {
366                                    StreamUtil.cleanUp(inputStream);
367                            }
368                    }
369    
370                    Field field = new Field(
371                            structureId, fieldName, fieldValues, serviceContext.getLocale());
372    
373                    fields.put(field);
374    
375                    StorageEngineUtil.update(storageId, fields, true, serviceContext);
376            }
377    
378            protected DDMStructure getDDMStructure(
379                            long ddmStructureId, long ddmTemplateId)
380                    throws PortalException, SystemException {
381    
382                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
383                            ddmStructureId);
384    
385                    try {
386                            DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
387                                    ddmTemplateId);
388    
389                            // Clone ddmStructure to make sure changes are never persisted
390    
391                            ddmStructure = (DDMStructure)ddmStructure.clone();
392    
393                            ddmStructure.setXsd(ddmTemplate.getScript());
394                    }
395                    catch (NoSuchTemplateException nste) {
396                    }
397    
398                    return ddmStructure;
399            }
400    
401            protected List<String> getFieldNames(
402                            DDMStructure ddmStructure, String fieldName, String fieldNamespace,
403                            JSONObject repeatableFieldsMapJSONObject)
404                    throws PortalException, SystemException {
405    
406                    List<String> fieldNames = new ArrayList<String>();
407    
408                    fieldNames.add(fieldNamespace + fieldName);
409    
410                    boolean repeatable = ddmStructure.isFieldRepeatable(fieldName);
411    
412                    if (repeatable && (repeatableFieldsMapJSONObject != null)) {
413                            JSONArray jsonArray = repeatableFieldsMapJSONObject.getJSONArray(
414                                    fieldNamespace + fieldName);
415    
416                            for (int i = 0; i < jsonArray.length(); i++) {
417                                    fieldNames.add(
418                                            fieldNamespace + fieldName + jsonArray.getString(i));
419                            }
420                    }
421    
422                    return fieldNames;
423            }
424    
425            protected List<String> getFieldNames(
426                            long structureId, String fieldNamespace, String fieldName,
427                            ServiceContext serviceContext)
428                    throws PortalException, SystemException {
429    
430                    DDMStructure structure = DDMStructureLocalServiceUtil.getDDMStructure(
431                            structureId);
432    
433                    JSONObject repeatableFieldsMapJSONObject =
434                            getRepeatableFieldsMapJSONObject(serviceContext);
435    
436                    return getFieldNames(
437                            structure, fieldName, fieldNamespace,
438                            repeatableFieldsMapJSONObject);
439            }
440    
441            protected List<Serializable> getFieldValues(
442                            DDMStructure ddmStructure,
443                            JSONObject repeatabaleFieldsMapJSONObject, String fieldName,
444                            String fieldNamespace, ServiceContext serviceContext)
445                    throws PortalException, SystemException {
446    
447                    String fieldDataType = ddmStructure.getFieldDataType(fieldName);
448                    String fieldType = ddmStructure.getFieldType(fieldName);
449    
450                    List<String> fieldNames = getFieldNames(
451                            ddmStructure, fieldName, fieldNamespace,
452                            repeatabaleFieldsMapJSONObject);
453    
454                    List<Serializable> fieldValues = new ArrayList<Serializable>(
455                            fieldNames.size());
456    
457                    for (String fieldNameValue : fieldNames) {
458                            Serializable fieldValue = serviceContext.getAttribute(
459                                    fieldNameValue);
460    
461                            if (fieldDataType.equals(FieldConstants.DATE)) {
462                                    int fieldValueMonth = GetterUtil.getInteger(
463                                            serviceContext.getAttribute(fieldNameValue + "Month"));
464                                    int fieldValueDay = GetterUtil.getInteger(
465                                            serviceContext.getAttribute(fieldNameValue + "Day"));
466                                    int fieldValueYear = GetterUtil.getInteger(
467                                            serviceContext.getAttribute(fieldNameValue + "Year"));
468    
469                                    Date fieldValueDate = PortalUtil.getDate(
470                                            fieldValueMonth, fieldValueDay, fieldValueYear);
471    
472                                    if (fieldValueDate != null) {
473                                            fieldValue = String.valueOf(fieldValueDate.getTime());
474                                    }
475                            }
476    
477                            if ((fieldValue == null) ||
478                                    fieldDataType.equals(FieldConstants.FILE_UPLOAD)) {
479    
480                                    return null;
481                            }
482    
483                            if (fieldType.equals(DDMImpl.TYPE_RADIO) ||
484                                    fieldType.equals(DDMImpl.TYPE_SELECT)) {
485    
486                                    if (fieldValue instanceof String) {
487                                            fieldValue = new String[] {String.valueOf(fieldValue)};
488                                    }
489    
490                                    fieldValue = JSONFactoryUtil.serialize(fieldValue);
491                            }
492    
493                            Serializable fieldValueSerializable =
494                                    FieldConstants.getSerializable(
495                                            fieldDataType, GetterUtil.getString(fieldValue));
496    
497                            fieldValues.add(fieldValueSerializable);
498                    }
499    
500                    return fieldValues;
501            }
502    
503            protected JSONObject getRepeatableFieldsMapJSONObject(
504                    ServiceContext serviceContext) {
505    
506                    try {
507                            String repeatabaleFieldsMap = GetterUtil.getString(
508                                    serviceContext.getAttribute("__repeatabaleFieldsMap"));
509    
510                            return JSONFactoryUtil.createJSONObject(repeatabaleFieldsMap);
511                    }
512                    catch (Exception e) {
513                            return null;
514                    }
515            }
516    
517            protected String storeFieldFile(
518                            BaseModel<?> baseModel, String fieldName, InputStream inputStream,
519                            ServiceContext serviceContext)
520                    throws Exception {
521    
522                    String dirName = getFileUploadPath(baseModel);
523    
524                    try {
525                            DLStoreUtil.addDirectory(
526                                    serviceContext.getCompanyId(), CompanyConstants.SYSTEM,
527                                    dirName);
528                    }
529                    catch (DuplicateDirectoryException dde) {
530                    }
531    
532                    String fileName = dirName + StringPool.SLASH + fieldName;
533    
534                    try {
535                            DLStoreUtil.addFile(
536                                    serviceContext.getCompanyId(), CompanyConstants.SYSTEM,
537                                    fileName, inputStream);
538                    }
539                    catch (DuplicateFileException dfe) {
540                    }
541    
542                    return fileName;
543            }
544    
545    }