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