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.JSONFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONObject;
021    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
023    import com.liferay.portal.kernel.upload.UploadRequest;
024    import com.liferay.portal.kernel.util.FileUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.ListUtil;
027    import com.liferay.portal.kernel.util.LocaleUtil;
028    import com.liferay.portal.kernel.util.MimeTypesUtil;
029    import com.liferay.portal.kernel.util.OrderByComparator;
030    import com.liferay.portal.kernel.util.StreamUtil;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.kernel.util.UnicodeFormatter;
035    import com.liferay.portal.kernel.util.Validator;
036    import com.liferay.portal.model.BaseModel;
037    import com.liferay.portal.model.CompanyConstants;
038    import com.liferay.portal.service.ServiceContext;
039    import com.liferay.portal.util.PortalUtil;
040    import com.liferay.portal.util.PropsValues;
041    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
042    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadataModel;
043    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
044    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
045    import com.liferay.portlet.documentlibrary.store.Store;
046    import com.liferay.portlet.dynamicdatalists.model.DDLRecord;
047    import com.liferay.portlet.dynamicdatalists.model.DDLRecordModel;
048    import com.liferay.portlet.dynamicdatalists.model.DDLRecordVersion;
049    import com.liferay.portlet.dynamicdatamapping.NoSuchTemplateException;
050    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
051    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
052    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
053    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
054    import com.liferay.portlet.dynamicdatamapping.storage.Field;
055    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
056    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
057    import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
058    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureIdComparator;
059    import com.liferay.portlet.dynamicdatamapping.util.comparator.StructureModifiedDateComparator;
060    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateIdComparator;
061    import com.liferay.portlet.dynamicdatamapping.util.comparator.TemplateModifiedDateComparator;
062    
063    import java.io.File;
064    import java.io.IOException;
065    import java.io.InputStream;
066    import java.io.Serializable;
067    
068    import java.util.ArrayList;
069    import java.util.Date;
070    import java.util.Iterator;
071    import java.util.List;
072    import java.util.Locale;
073    import java.util.Set;
074    
075    import javax.servlet.http.HttpServletRequest;
076    import javax.servlet.http.HttpServletResponse;
077    
078    /**
079     * @author Eduardo Lundgren
080     * @author Brian Wing Shun Chan
081     * @author Eduardo Garcia
082     * @author Marcellus Tavares
083     */
084    @DoPrivileged
085    public class DDMImpl implements DDM {
086    
087            public static final String FIELDS_DISPLAY_NAME = "_fieldsDisplay";
088    
089            public static final String INSTANCE_SEPARATOR = "_INSTANCE_";
090    
091            public static final String TYPE_CHECKBOX = "checkbox";
092    
093            public static final String TYPE_DDM_DOCUMENTLIBRARY = "ddm-documentlibrary";
094    
095            public static final String TYPE_DDM_FILEUPLOAD = "ddm-fileupload";
096    
097            public static final String TYPE_DDM_LINK_TO_PAGE = "ddm-link-to-page";
098    
099            public static final String TYPE_RADIO = "radio";
100    
101            public static final String TYPE_SELECT = "select";
102    
103            public Fields getFields(
104                            long ddmStructureId, long ddmTemplateId,
105                            ServiceContext serviceContext)
106                    throws PortalException, SystemException {
107    
108                    return getFields(
109                            ddmStructureId, ddmTemplateId, StringPool.BLANK, serviceContext);
110            }
111    
112            public Fields getFields(
113                            long ddmStructureId, long ddmTemplateId, String fieldNamespace,
114                            ServiceContext serviceContext)
115                    throws PortalException, SystemException {
116    
117                    DDMStructure ddmStructure = getDDMStructure(
118                            ddmStructureId, ddmTemplateId);
119    
120                    Set<String> fieldNames = ddmStructure.getFieldNames();
121    
122                    Fields fields = new Fields();
123    
124                    for (String fieldName : fieldNames) {
125                            List<Serializable> fieldValues = getFieldValues(
126                                    ddmStructure, fieldName, fieldNamespace, serviceContext);
127    
128                            if ((fieldValues == null) || fieldValues.isEmpty()) {
129                                    continue;
130                            }
131    
132                            Field field = createField(
133                                    ddmStructure, fieldName, fieldValues, serviceContext);
134    
135                            fields.put(field);
136                    }
137    
138                    return fields;
139            }
140    
141            public Fields getFields(long ddmStructureId, ServiceContext serviceContext)
142                    throws PortalException, SystemException {
143    
144                    return getFields(ddmStructureId, 0, serviceContext);
145            }
146    
147            public Fields getFields(
148                            long ddmStructureId, String fieldNamespace,
149                            ServiceContext serviceContext)
150                    throws PortalException, SystemException {
151    
152                    return getFields(ddmStructureId, 0, fieldNamespace, serviceContext);
153            }
154    
155            public String[] getFieldsDisplayValues(Field fieldsDisplayField)
156                    throws Exception {
157    
158                    DDMStructure ddmStructure = fieldsDisplayField.getDDMStructure();
159    
160                    List<String> fieldsDisplayValues = new ArrayList<String>();
161    
162                    String[] values = StringUtil.split(
163                            (String)fieldsDisplayField.getValue());
164    
165                    for (String value : values) {
166                            String fieldName = StringUtil.extractFirst(
167                                    value, DDMImpl.INSTANCE_SEPARATOR);
168    
169                            if (ddmStructure.hasField(fieldName)) {
170                                    fieldsDisplayValues.add(fieldName);
171                            }
172                    }
173    
174                    return fieldsDisplayValues.toArray(
175                            new String[fieldsDisplayValues.size()]);
176            }
177    
178            public String getFileUploadPath(BaseModel<?> baseModel) {
179                    StringBundler sb = new StringBundler(7);
180    
181                    try {
182                            long primaryKey = 0;
183    
184                            String version = StringPool.BLANK;
185    
186                            if (baseModel instanceof DDLRecordModel) {
187                                    DDLRecord record = (DDLRecord)baseModel;
188    
189                                    primaryKey = record.getPrimaryKey();
190    
191                                    DDLRecordVersion recordVersion =
192                                            record.getLatestRecordVersion();
193    
194                                    version = recordVersion.getVersion();
195                            }
196                            else if (baseModel instanceof DLFileEntryMetadataModel) {
197                                    DLFileEntryMetadata fileEntryMetadata =
198                                            (DLFileEntryMetadata)baseModel;
199    
200                                    primaryKey = fileEntryMetadata.getPrimaryKey();
201    
202                                    DLFileVersion fileVersion = fileEntryMetadata.getFileVersion();
203    
204                                    version = fileVersion.getVersion();
205                            }
206    
207                            sb.append("ddm");
208                            sb.append(StringPool.SLASH);
209                            sb.append(baseModel.getModelClassName());
210                            sb.append(StringPool.SLASH);
211                            sb.append(primaryKey);
212                            sb.append(StringPool.SLASH);
213                            sb.append(version);
214                    }
215                    catch (Exception e) {
216                    }
217    
218                    return sb.toString();
219            }
220    
221            public OrderByComparator getStructureOrderByComparator(
222                    String orderByCol, String orderByType) {
223    
224                    boolean orderByAsc = false;
225    
226                    if (orderByType.equals("asc")) {
227                            orderByAsc = true;
228                    }
229    
230                    OrderByComparator orderByComparator = null;
231    
232                    if (orderByCol.equals("id")) {
233                            orderByComparator = new StructureIdComparator(orderByAsc);
234                    }
235                    else if (orderByCol.equals("modified-date")) {
236                            orderByComparator = new StructureModifiedDateComparator(orderByAsc);
237                    }
238    
239                    return orderByComparator;
240            }
241    
242            public OrderByComparator getTemplateOrderByComparator(
243                    String orderByCol, String orderByType) {
244    
245                    boolean orderByAsc = false;
246    
247                    if (orderByType.equals("asc")) {
248                            orderByAsc = true;
249                    }
250    
251                    OrderByComparator orderByComparator = null;
252    
253                    if (orderByCol.equals("id")) {
254                            orderByComparator = new TemplateIdComparator(orderByAsc);
255                    }
256                    else if (orderByCol.equals("modified-date")) {
257                            orderByComparator = new TemplateModifiedDateComparator(orderByAsc);
258                    }
259    
260                    return orderByComparator;
261            }
262    
263            public Fields mergeFields(Fields newFields, Fields existingFields) {
264                    Iterator<Field> itr = newFields.iterator(true);
265    
266                    while (itr.hasNext()) {
267                            Field newField = itr.next();
268    
269                            Field existingField = existingFields.get(newField.getName());
270    
271                            if (existingField == null) {
272                                    existingFields.put(newField);
273                            }
274                            else {
275                                    for (Locale locale : newField.getAvailableLocales()) {
276                                            existingField.setValues(locale, newField.getValues(locale));
277                                    }
278    
279                                    existingField.setDefaultLocale(newField.getDefaultLocale());
280                            }
281    
282                    }
283    
284                    return existingFields;
285            }
286    
287            public void sendFieldFile(
288                            HttpServletRequest request, HttpServletResponse response,
289                            Field field, int valueIndex)
290                    throws Exception {
291    
292                    if (field == null) {
293                            return;
294                    }
295    
296                    DDMStructure structure = field.getDDMStructure();
297    
298                    Locale locale = PortalUtil.getLocale(request);
299    
300                    Serializable fieldValue = field.getValue(locale, valueIndex);
301    
302                    JSONObject fileJSONObject = JSONFactoryUtil.createJSONObject(
303                            String.valueOf(fieldValue));
304    
305                    String fileName = fileJSONObject.getString("name");
306                    String filePath = fileJSONObject.getString("path");
307    
308                    InputStream is = DLStoreUtil.getFileAsStream(
309                            structure.getCompanyId(), CompanyConstants.SYSTEM, filePath);
310                    long contentLength = DLStoreUtil.getFileSize(
311                            structure.getCompanyId(), CompanyConstants.SYSTEM, filePath);
312                    String contentType = MimeTypesUtil.getContentType(fileName);
313    
314                    ServletResponseUtil.sendFile(
315                            request, response, fileName, is, contentLength, contentType);
316            }
317    
318            public void uploadFieldFile(
319                            long structureId, long storageId, BaseModel<?> baseModel,
320                            String fieldName, ServiceContext serviceContext)
321                    throws Exception {
322    
323                    uploadFieldFile(
324                            structureId, storageId, baseModel, fieldName, StringPool.BLANK,
325                            serviceContext);
326            }
327    
328            public void uploadFieldFile(
329                            long structureId, long storageId, BaseModel<?> baseModel,
330                            String fieldName, String fieldNamespace,
331                            ServiceContext serviceContext)
332                    throws Exception {
333    
334                    HttpServletRequest request = serviceContext.getRequest();
335    
336                    if (!(request instanceof UploadRequest)) {
337                            return;
338                    }
339    
340                    UploadRequest uploadRequest = (UploadRequest)request;
341    
342                    Fields fields = StorageEngineUtil.getFields(storageId);
343    
344                    List<String> fieldNames = getFieldNames(
345                            fieldNamespace, fieldName, serviceContext);
346    
347                    List<Serializable> fieldValues = new ArrayList<Serializable>(
348                            fieldNames.size());
349    
350                    for (int i = 0; i < fieldNames.size(); i++) {
351                            InputStream inputStream = null;
352    
353                            try {
354                                    String fileName = uploadRequest.getFileName(fieldNames.get(i));
355    
356                                    inputStream = uploadRequest.getFileAsStream(
357                                            fieldNames.get(i), true);
358    
359                                    if ((inputStream == null) && fields.contains(fieldName)) {
360                                            Field field = fields.get(fieldName);
361    
362                                            Serializable fieldValue = field.getValue(
363                                                    field.getDefaultLocale(), i);
364    
365                                            if (fieldValue != null) {
366                                                    JSONObject recordFileJSONObject =
367                                                            JSONFactoryUtil.createJSONObject(
368                                                                    String.valueOf(fieldValue));
369    
370                                                    fileName = recordFileJSONObject.getString("name");
371    
372                                                    inputStream = DLStoreUtil.getFileAsStream(
373                                                            serviceContext.getCompanyId(),
374                                                            CompanyConstants.SYSTEM,
375                                                            recordFileJSONObject.getString("path"));
376                                            }
377                                    }
378    
379                                    if (inputStream != null) {
380                                            String filePath = storeFieldFile(
381                                                    baseModel, fieldName, inputStream, serviceContext);
382    
383                                            JSONObject recordFileJSONObject =
384                                                    JSONFactoryUtil.createJSONObject();
385    
386                                            recordFileJSONObject.put("name", fileName);
387                                            recordFileJSONObject.put("path", filePath);
388                                            recordFileJSONObject.put(
389                                                    "className", baseModel.getModelClassName());
390                                            recordFileJSONObject.put(
391                                                    "classPK",
392                                                    String.valueOf(baseModel.getPrimaryKeyObj()));
393    
394                                            String fieldValue = recordFileJSONObject.toString();
395    
396                                            fieldValues.add(fieldValue);
397                                    }
398                            }
399                            finally {
400                                    StreamUtil.cleanUp(inputStream);
401                            }
402                    }
403    
404                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
405                            structureId);
406    
407                    Field field = createField(
408                            ddmStructure, fieldName, fieldValues, serviceContext);
409    
410                    fields.put(field);
411    
412                    StorageEngineUtil.update(storageId, fields, true, serviceContext);
413            }
414    
415            protected Field createField(
416                            DDMStructure ddmStructure, String fieldName,
417                            List<Serializable> fieldValues, ServiceContext serviceContext)
418                    throws PortalException, SystemException {
419    
420                    Field field = new Field();
421    
422                    field.setDDMStructureId(ddmStructure.getStructureId());
423    
424                    String languageId = GetterUtil.getString(
425                            serviceContext.getAttribute("languageId"),
426                            serviceContext.getLanguageId());
427    
428                    Locale locale = LocaleUtil.fromLanguageId(languageId);
429    
430                    String defaultLanguageId = GetterUtil.getString(
431                            serviceContext.getAttribute("defaultLanguageId"));
432    
433                    Locale defaultLocale = LocaleUtil.fromLanguageId(defaultLanguageId);
434    
435                    if (ddmStructure.isFieldPrivate(fieldName)) {
436                            locale = LocaleUtil.getDefault();
437    
438                            defaultLocale = LocaleUtil.getDefault();
439                    }
440    
441                    field.setDefaultLocale(defaultLocale);
442    
443                    field.setName(fieldName);
444                    field.setValues(locale, fieldValues);
445    
446                    return field;
447            }
448    
449            protected DDMStructure getDDMStructure(
450                            long ddmStructureId, long ddmTemplateId)
451                    throws PortalException, SystemException {
452    
453                    DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(
454                            ddmStructureId);
455    
456                    try {
457                            DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(
458                                    ddmTemplateId);
459    
460                            // Clone ddmStructure to make sure changes are never persisted
461    
462                            ddmStructure = (DDMStructure)ddmStructure.clone();
463    
464                            ddmStructure.setXsd(ddmTemplate.getScript());
465                    }
466                    catch (NoSuchTemplateException nste) {
467                    }
468    
469                    return ddmStructure;
470            }
471    
472            protected List<String> getFieldNames(
473                    String fieldNamespace, String fieldName,
474                    ServiceContext serviceContext) {
475    
476                    String[] fieldsDisplayValues = StringUtil.split(
477                            (String)serviceContext.getAttribute(
478                                    fieldNamespace + FIELDS_DISPLAY_NAME));
479    
480                    List<String> privateFieldNames = ListUtil.fromArray(
481                            PropsValues.DYNAMIC_DATA_MAPPING_STRUCTURE_PRIVATE_FIELD_NAMES);
482    
483                    List<String> fieldNames = new ArrayList<String>();
484    
485                    if ((fieldsDisplayValues.length == 0) ||
486                            privateFieldNames.contains(fieldName)) {
487    
488                            fieldNames.add(fieldNamespace + fieldName);
489                    }
490                    else {
491                            for (String namespacedFieldName : fieldsDisplayValues) {
492                                    String fieldNameValue = StringUtil.extractFirst(
493                                            namespacedFieldName, INSTANCE_SEPARATOR);
494    
495                                    if (fieldNameValue.equals(fieldName)) {
496                                            fieldNames.add(fieldNamespace + namespacedFieldName);
497                                    }
498                            }
499                    }
500    
501                    return fieldNames;
502            }
503    
504            protected List<Serializable> getFieldValues(
505                            DDMStructure ddmStructure, String fieldName, String fieldNamespace,
506                            ServiceContext serviceContext)
507                    throws PortalException, SystemException {
508    
509                    String fieldDataType = ddmStructure.getFieldDataType(fieldName);
510                    String fieldType = ddmStructure.getFieldType(fieldName);
511    
512                    List<String> fieldNames = getFieldNames(
513                            fieldNamespace, fieldName, serviceContext);
514    
515                    List<Serializable> fieldValues = new ArrayList<Serializable>(
516                            fieldNames.size());
517    
518                    for (String fieldNameValue : fieldNames) {
519                            Serializable fieldValue = serviceContext.getAttribute(
520                                    fieldNameValue);
521    
522                            if (fieldDataType.equals(FieldConstants.DATE)) {
523                                    int fieldValueMonth = GetterUtil.getInteger(
524                                            serviceContext.getAttribute(fieldNameValue + "Month"));
525                                    int fieldValueDay = GetterUtil.getInteger(
526                                            serviceContext.getAttribute(fieldNameValue + "Day"));
527                                    int fieldValueYear = GetterUtil.getInteger(
528                                            serviceContext.getAttribute(fieldNameValue + "Year"));
529    
530                                    Date fieldValueDate = PortalUtil.getDate(
531                                            fieldValueMonth, fieldValueDay, fieldValueYear);
532    
533                                    if (fieldValueDate != null) {
534                                            fieldValue = String.valueOf(fieldValueDate.getTime());
535                                    }
536                            }
537                            else if (fieldDataType.equals(FieldConstants.IMAGE) &&
538                                             Validator.isNull(fieldValue)) {
539    
540                                    HttpServletRequest request = serviceContext.getRequest();
541    
542                                    if (!(request instanceof UploadRequest)) {
543                                            return null;
544                                    }
545    
546                                    UploadRequest uploadRequest = (UploadRequest)request;
547    
548                                    File file = uploadRequest.getFile(fieldNameValue);
549    
550                                    try {
551                                            byte[] bytes = FileUtil.getBytes(file);
552    
553                                            if ((bytes != null) && (bytes.length > 0)) {
554                                                    fieldValue = UnicodeFormatter.bytesToHex(bytes);
555                                            }
556                                    }
557                                    catch (IOException ioe) {
558                                            return null;
559                                    }
560                            }
561    
562                            if ((fieldValue == null) ||
563                                    fieldDataType.equals(FieldConstants.FILE_UPLOAD)) {
564    
565                                    return null;
566                            }
567    
568                            if (DDMImpl.TYPE_RADIO.equals(fieldType) ||
569                                    DDMImpl.TYPE_SELECT.equals(fieldType)) {
570    
571                                    if (fieldValue instanceof String) {
572                                            fieldValue = new String[] {String.valueOf(fieldValue)};
573                                    }
574    
575                                    fieldValue = JSONFactoryUtil.serialize(fieldValue);
576                            }
577    
578                            Serializable fieldValueSerializable =
579                                    FieldConstants.getSerializable(
580                                            fieldDataType, GetterUtil.getString(fieldValue));
581    
582                            fieldValues.add(fieldValueSerializable);
583                    }
584    
585                    return fieldValues;
586            }
587    
588            protected String storeFieldFile(
589                            BaseModel<?> baseModel, String fieldName, InputStream inputStream,
590                            ServiceContext serviceContext)
591                    throws PortalException, SystemException {
592    
593                    long companyId = serviceContext.getCompanyId();
594    
595                    String dirName = getFileUploadPath(baseModel);
596    
597                    if (!DLStoreUtil.hasDirectory(
598                                    companyId, CompanyConstants.SYSTEM, dirName)) {
599    
600                            DLStoreUtil.addDirectory(
601                                    companyId, CompanyConstants.SYSTEM, dirName);
602                    }
603    
604                    String fileName = dirName + StringPool.SLASH + fieldName;
605    
606                    if (DLStoreUtil.hasFile(
607                                    companyId, CompanyConstants.SYSTEM, fileName,
608                                    Store.VERSION_DEFAULT)) {
609    
610                            DLStoreUtil.deleteFile(
611                                    companyId, CompanyConstants.SYSTEM, fileName,
612                                    Store.VERSION_DEFAULT);
613                    }
614    
615                    DLStoreUtil.addFile(
616                            companyId, CompanyConstants.SYSTEM, fileName, false, inputStream);
617    
618                    return fileName;
619            }
620    
621    }