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.portal.verify;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.json.JSONFactoryUtil;
019    import com.liferay.portal.kernel.json.JSONObject;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.repository.model.FileEntry;
023    import com.liferay.portal.kernel.repository.model.FileVersion;
024    import com.liferay.portal.kernel.repository.model.Folder;
025    import com.liferay.portal.kernel.util.CharPool;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.MimeTypesUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.kernel.xml.Document;
032    import com.liferay.portal.kernel.xml.Element;
033    import com.liferay.portal.kernel.xml.Node;
034    import com.liferay.portal.kernel.xml.SAXReaderUtil;
035    import com.liferay.portal.kernel.xml.XPath;
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.portlet.documentlibrary.NoSuchFolderException;
041    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
042    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
043    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
044    import com.liferay.portlet.documentlibrary.model.DLSyncConstants;
045    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
046    import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
047    import com.liferay.portlet.documentlibrary.service.DLFileEntryMetadataLocalServiceUtil;
048    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
049    import com.liferay.portlet.dynamicdatalists.model.DDLRecord;
050    import com.liferay.portlet.dynamicdatalists.model.DDLRecordModel;
051    import com.liferay.portlet.dynamicdatalists.model.DDLRecordSet;
052    import com.liferay.portlet.dynamicdatalists.model.DDLRecordVersion;
053    import com.liferay.portlet.dynamicdatalists.service.DDLRecordLocalServiceUtil;
054    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
055    import com.liferay.portlet.dynamicdatamapping.model.DDMStructureLink;
056    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
057    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplateConstants;
058    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLinkLocalServiceUtil;
059    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
060    import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
061    import com.liferay.portlet.dynamicdatamapping.storage.Field;
062    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
063    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
064    import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
065    import com.liferay.portlet.dynamicdatamapping.util.DDMXMLUtil;
066    
067    import java.io.File;
068    import java.io.Serializable;
069    
070    import java.util.HashMap;
071    import java.util.List;
072    import java.util.Map;
073    
074    /**
075     * @author Marcellus Tavares
076     */
077    public class VerifyDynamicDataMapping extends VerifyProcess {
078    
079            protected FileEntry addFileEntry(
080                            long companyId, long userId, long groupId, long folderId,
081                            String fileName, String filePath, int status)
082                    throws Exception {
083    
084                    String contentType = MimeTypesUtil.getContentType(fileName);
085    
086                    String title = fileName;
087    
088                    int index = title.indexOf(CharPool.PERIOD);
089    
090                    if (index > 0) {
091                            title = title.substring(0, index);
092                    }
093    
094                    try {
095                            File file = DLStoreUtil.getFile(
096                                    companyId, CompanyConstants.SYSTEM, filePath);
097    
098                            ServiceContext serviceContext = createServiceContext();
099    
100                            FileEntry fileEntry = DLAppLocalServiceUtil.addFileEntry(
101                                    userId, groupId, folderId, fileName, contentType, title,
102                                    StringPool.BLANK, StringPool.BLANK, file, serviceContext);
103    
104                            updateFileEntryStatus(fileEntry, status, serviceContext);
105    
106                            return fileEntry;
107                    }
108                    catch (Exception e) {
109                            if (_log.isWarnEnabled()) {
110                                    _log.warn("Unable to add file entry " + fileName, e);
111                            }
112    
113                            return null;
114                    }
115            }
116    
117            protected Folder addFolder(
118                            long userId, long groupId, long primaryKey, String fieldName)
119                    throws Exception {
120    
121                    Folder ddmFolder = addFolder(
122                            userId, groupId, DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, "DDM",
123                            StringPool.BLANK);
124    
125                    Folder primaryKeyFolder = addFolder(
126                            userId, groupId, ddmFolder.getFolderId(),
127                            String.valueOf(primaryKey), StringPool.BLANK);
128    
129                    return addFolder(
130                            userId, groupId, primaryKeyFolder.getFolderId(), fieldName,
131                            StringPool.BLANK);
132            }
133    
134            protected Folder addFolder(
135                            long userId, long groupId, long parentFolderId, String name,
136                            String description)
137                    throws Exception {
138    
139                    try {
140                            return DLAppLocalServiceUtil.getFolder(
141                                    groupId, parentFolderId, name);
142                    }
143                    catch (NoSuchFolderException nsfe) {
144                            return DLAppLocalServiceUtil.addFolder(
145                                    userId, groupId, parentFolderId, name, description,
146                                    createServiceContext());
147                    }
148            }
149    
150            protected boolean createDefaultMetadataElement(
151                    Element dynamicElementElement, String defaultLanguageId) {
152    
153                    boolean hasDefaultMetadataElement = hasDefaultMetadataElement(
154                            dynamicElementElement, defaultLanguageId);
155    
156                    if (hasDefaultMetadataElement) {
157                            return false;
158                    }
159    
160                    Element metadataElement = dynamicElementElement.addElement("meta-data");
161    
162                    metadataElement.addAttribute("locale", defaultLanguageId);
163    
164                    Element entryElement = metadataElement.addElement("entry");
165    
166                    entryElement.addAttribute("name", "label");
167                    entryElement.addCDATA(StringPool.BLANK);
168    
169                    return true;
170            }
171    
172            protected ServiceContext createServiceContext() {
173                    ServiceContext serviceContext = new ServiceContext();
174    
175                    serviceContext.setAddGroupPermissions(true);
176                    serviceContext.setAddGuestPermissions(true);
177    
178                    return serviceContext;
179            }
180    
181            @Override
182            protected void doVerify() throws Exception {
183                    setUpClassNameIds();
184    
185                    List<DDMStructure> structures =
186                            DDMStructureLocalServiceUtil.getStructures();
187    
188                    for (DDMStructure structure : structures) {
189                            verifyStructure(structure);
190    
191                            updateFileUploadReferences(structure);
192                    }
193            }
194    
195            protected String getFileUploadPath(BaseModel<?> baseModel)
196                    throws Exception {
197    
198                    StringBundler sb = new StringBundler(7);
199    
200                    long primaryKey = 0;
201    
202                    String version = StringPool.BLANK;
203    
204                    if (baseModel instanceof DDLRecordModel) {
205                            DDLRecord ddlRecord = (DDLRecord)baseModel;
206    
207                            primaryKey = ddlRecord.getPrimaryKey();
208    
209                            DDLRecordVersion ddlRecordVersion = ddlRecord.getRecordVersion();
210    
211                            version = ddlRecordVersion.getVersion();
212                    }
213                    else {
214                            DLFileEntryMetadata dlFileEntryMetadata =
215                                    (DLFileEntryMetadata)baseModel;
216    
217                            primaryKey = dlFileEntryMetadata.getPrimaryKey();
218    
219                            DLFileVersion dlFileVersion = dlFileEntryMetadata.getFileVersion();
220    
221                            version = dlFileVersion.getVersion();
222                    }
223    
224                    sb.append("ddm");
225                    sb.append(StringPool.SLASH);
226                    sb.append(baseModel.getModelClassName());
227                    sb.append(StringPool.SLASH);
228                    sb.append(primaryKey);
229                    sb.append(StringPool.SLASH);
230                    sb.append(version);
231    
232                    return sb.toString();
233            }
234    
235            protected String getJSON(FileEntry fileEntry) {
236                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
237    
238                    jsonObject.put("groupId", fileEntry.getGroupId());
239                    jsonObject.put("uuid", fileEntry.getUuid());
240    
241                    return jsonObject.toString();
242            }
243    
244            protected boolean hasDefaultMetadataElement(
245                    Element dynamicElementElement, String defaultLanguageId) {
246    
247                    List<Element> metadataElements = dynamicElementElement.elements(
248                            "meta-data");
249    
250                    for (Element metadataElement : metadataElements) {
251                            String languageId = metadataElement.attributeValue("locale");
252    
253                            if (languageId.equals(defaultLanguageId)) {
254                                    return true;
255                            }
256                    }
257    
258                    return false;
259            }
260    
261            protected boolean hasFileUploadFields(DDMStructure structure)
262                    throws Exception {
263    
264                    Map<String, Map<String, String>> fieldsMap = structure.getFieldsMap();
265    
266                    for (Map<String, String> field : fieldsMap.values()) {
267                            String dataType = field.get(FieldConstants.DATA_TYPE);
268    
269                            if (dataType.equals("file-upload")) {
270                                    return true;
271                            }
272                    }
273    
274                    return false;
275            }
276    
277            protected void setUpClassNameIds() {
278                    _ddlRecordSetClassNameId = PortalUtil.getClassNameId(
279                            DDLRecordSet.class);
280                    _ddmStructureClassNameId = PortalUtil.getClassNameId(
281                            DDMStructure.class);
282                    _dlFileEntryMetadataClassNameId = PortalUtil.getClassNameId(
283                            DLFileEntryMetadata.class);
284            }
285    
286            protected void updateDDLFileUploadReferences(long ddlRecordSetId)
287                    throws Exception {
288    
289                    List<DDLRecord> ddlRecords = DDLRecordLocalServiceUtil.getRecords(
290                            ddlRecordSetId);
291    
292                    for (DDLRecord ddlRecord : ddlRecords) {
293                            updateFileUploadReferences(
294                                    ddlRecord.getCompanyId(), ddlRecord.getDDMStorageId(),
295                                    ddlRecord.getUserId(), ddlRecord.getGroupId(), ddlRecord,
296                                    ddlRecord.getStatus());
297                    }
298            }
299    
300            protected void updateDLFileUploadReferences(long dlFileEntryMetadataId)
301                    throws Exception {
302    
303                    DLFileEntryMetadata dlFileEntryMetadata =
304                            DLFileEntryMetadataLocalServiceUtil.getFileEntryMetadata(
305                                    dlFileEntryMetadataId);
306    
307                    FileEntry fileEntry = DLAppLocalServiceUtil.getFileEntry(
308                            dlFileEntryMetadata.getFileEntryId());
309    
310                    FileVersion fileVersion = fileEntry.getFileVersion();
311    
312                    updateFileUploadReferences(
313                            fileEntry.getCompanyId(), dlFileEntryMetadata.getDDMStorageId(),
314                            fileEntry.getUserId(), fileEntry.getGroupId(), dlFileEntryMetadata,
315                            fileVersion.getStatus());
316            }
317    
318            protected void updateFieldValues(
319                            long storageId, Map<String, String> fieldValues)
320                    throws Exception {
321    
322                    Fields fields = new Fields();
323    
324                    for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
325                            Field field = new Field(
326                                    storageId, entry.getKey(), entry.getValue());
327    
328                            fields.put(field);
329                    }
330    
331                    ServiceContext serviceContext = new ServiceContext();
332    
333                    StorageEngineUtil.update(storageId, fields, true, serviceContext);
334            }
335    
336            protected void updateFileEntryStatus(
337                            FileEntry fileEntry, int status, ServiceContext serviceContext)
338                    throws Exception {
339    
340                    FileVersion fileVersion = fileEntry.getFileVersion();
341    
342                    Map<String, Serializable> workflowContext =
343                            new HashMap<String, Serializable>();
344    
345                    workflowContext.put("event", DLSyncConstants.EVENT_ADD);
346    
347                    DLFileEntryLocalServiceUtil.updateStatus(
348                            fileVersion.getUserId(), fileVersion.getFileVersionId(), status,
349                            workflowContext, serviceContext);
350            }
351    
352            protected void updateFileUploadReferences(DDMStructure structure)
353                    throws Exception {
354    
355                    if (!hasFileUploadFields(structure)) {
356                            return;
357                    }
358    
359                    List<DDMStructureLink> structureLinks =
360                            DDMStructureLinkLocalServiceUtil.getStructureLinks(
361                                    structure.getStructureId(), QueryUtil.ALL_POS,
362                                    QueryUtil.ALL_POS);
363    
364                    for (DDMStructureLink structureLink : structureLinks) {
365                            updateFileUploadReferences(structureLink);
366                    }
367    
368                    updateStructure(structure, updateXSD(structure.getXsd()));
369    
370                    List<DDMTemplate> templates = DDMTemplateLocalServiceUtil.getTemplates(
371                            structure.getGroupId(), _ddmStructureClassNameId,
372                            structure.getStructureId(),
373                            DDMTemplateConstants.TEMPLATE_TYPE_FORM);
374    
375                    for (DDMTemplate template : templates) {
376                            updateTemplate(template, updateXSD(template.getScript()));
377                    }
378            }
379    
380            protected void updateFileUploadReferences(DDMStructureLink structureLink)
381                    throws Exception {
382    
383                    long classNameId = structureLink.getClassNameId();
384    
385                    if (classNameId == _ddlRecordSetClassNameId) {
386                            updateDDLFileUploadReferences(structureLink.getClassPK());
387                    }
388                    else if (classNameId == _dlFileEntryMetadataClassNameId) {
389                            updateDLFileUploadReferences(structureLink.getClassPK());
390                    }
391            }
392    
393            protected void updateFileUploadReferences(
394                            long companyId, long storageId, long userId, long groupId,
395                            BaseModel<?> baseModel, int status)
396                    throws Exception {
397    
398                    Map<String, String> fieldValues = new HashMap<String, String>();
399    
400                    Fields fields = StorageEngineUtil.getFields(storageId);
401    
402                    for (Field field : fields) {
403                            String dataType = field.getDataType();
404    
405                            if (!dataType.equals("file-upload") || (field.getValue() == null)) {
406                                    continue;
407                            }
408    
409                            long primaryKey = GetterUtil.getLong(baseModel.getPrimaryKeyObj());
410    
411                            Folder folder = addFolder(
412                                    userId, groupId, primaryKey, field.getName());
413    
414                            String valueString = String.valueOf(field.getValue());
415    
416                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
417                                    valueString);
418    
419                            String filePath =
420                                    getFileUploadPath(baseModel) + StringPool.SLASH +
421                                            field.getName();
422    
423                            FileEntry fileEntry = addFileEntry(
424                                    companyId, userId, groupId, folder.getFolderId(),
425                                    jsonObject.getString("name"), filePath, status);
426    
427                            if (fileEntry != null) {
428                                    fieldValues.put(field.getName(), getJSON(fileEntry));
429                            }
430                    }
431    
432                    updateFieldValues(storageId, fieldValues);
433            }
434    
435            protected void updateStructure(DDMStructure structure, String xsd)
436                    throws Exception {
437    
438                    xsd = DDMXMLUtil.formatXML(xsd);
439    
440                    structure.setXsd(xsd);
441    
442                    DDMStructureLocalServiceUtil.updateDDMStructure(structure);
443            }
444    
445            protected void updateTemplate(DDMTemplate template, String script)
446                    throws Exception {
447    
448                    script = DDMXMLUtil.formatXML(script);
449    
450                    template.setScript(script);
451    
452                    DDMTemplateLocalServiceUtil.updateDDMTemplate(template);
453            }
454    
455            protected String updateXSD(String xsd) throws Exception {
456                    Document document = SAXReaderUtil.read(xsd);
457    
458                    Element rootElement = document.getRootElement();
459    
460                    List<Element> dynamicElementElements = rootElement.elements(
461                            "dynamic-element");
462    
463                    for (Element dynamicElementElement : dynamicElementElements) {
464                            updateXSDDynamicElement(dynamicElementElement);
465                    }
466    
467                    return document.asXML();
468            }
469    
470            protected void updateXSDDynamicElement(Element element) {
471                    String dataType = element.attributeValue("dataType");
472    
473                    if (Validator.equals(dataType, "file-upload")) {
474                            element.addAttribute("dataType", "document-library");
475                            element.addAttribute("type", "ddm-documentlibrary");
476                    }
477    
478                    List<Element> dynamicElementElements = element.elements(
479                            "dynamic-element");
480    
481                    for (Element dynamicElementElement : dynamicElementElements) {
482                            updateXSDDynamicElement(dynamicElementElement);
483                    }
484            }
485    
486            protected void verifyStructure(DDMStructure structure) throws Exception {
487                    boolean modified = false;
488    
489                    String defaultLanguageId = structure.getDefaultLanguageId();
490    
491                    XPath xPathSelector = SAXReaderUtil.createXPath("//dynamic-element");
492    
493                    Document document = structure.getDocument();
494    
495                    List<Node> nodes = xPathSelector.selectNodes(document);
496    
497                    for (Node node : nodes) {
498                            Element dynamicElementElement = (Element)node;
499    
500                            if (createDefaultMetadataElement(
501                                            dynamicElementElement, defaultLanguageId)) {
502    
503                                    modified = true;
504                            }
505                    }
506    
507                    if (modified) {
508                            updateStructure(structure, document.asXML());
509                    }
510            }
511    
512            private static Log _log = LogFactoryUtil.getLog(
513                    VerifyDynamicDataMapping.class);
514    
515            private long _ddlRecordSetClassNameId;
516            private long _ddmStructureClassNameId;
517            private long _dlFileEntryMetadataClassNameId;
518    
519    }