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