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