001
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.HashSet;
076 import java.util.List;
077 import java.util.Map;
078 import java.util.Set;
079
080
083 public class VerifyDynamicDataMapping extends VerifyProcess {
084
085 protected FileEntry addFileEntry(
086 long companyId, long userId, long groupId, long folderId,
087 String fileName, String filePath, int status)
088 throws Exception {
089
090 String contentType = MimeTypesUtil.getContentType(fileName);
091
092 String title = fileName;
093
094 int index = title.indexOf(CharPool.PERIOD);
095
096 if (index > 0) {
097 title = title.substring(0, index);
098 }
099
100 try {
101 File file = DLStoreUtil.getFile(
102 companyId, CompanyConstants.SYSTEM, filePath);
103
104 ServiceContext serviceContext = createServiceContext();
105
106 FileEntry fileEntry = DLAppLocalServiceUtil.addFileEntry(
107 userId, groupId, folderId, fileName, contentType, title,
108 StringPool.BLANK, StringPool.BLANK, file, serviceContext);
109
110 updateFileEntryStatus(fileEntry, status, serviceContext);
111
112 return fileEntry;
113 }
114 catch (Exception e) {
115 if (_log.isWarnEnabled()) {
116 _log.warn("Unable to add file entry " + fileName, e);
117 }
118
119 return null;
120 }
121 }
122
123 protected Folder addFolder(
124 long userId, long groupId, long primaryKey, String fieldName)
125 throws Exception {
126
127 Folder ddmFolder = addFolder(
128 userId, groupId, DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, "DDM",
129 StringPool.BLANK);
130
131 Folder primaryKeyFolder = addFolder(
132 userId, groupId, ddmFolder.getFolderId(),
133 String.valueOf(primaryKey), StringPool.BLANK);
134
135 return addFolder(
136 userId, groupId, primaryKeyFolder.getFolderId(), fieldName,
137 StringPool.BLANK);
138 }
139
140 protected Folder addFolder(
141 long userId, long groupId, long parentFolderId, String name,
142 String description)
143 throws Exception {
144
145 try {
146 return DLAppLocalServiceUtil.getFolder(
147 groupId, parentFolderId, name);
148 }
149 catch (NoSuchFolderException nsfe) {
150 return DLAppLocalServiceUtil.addFolder(
151 userId, groupId, parentFolderId, name, description,
152 createServiceContext());
153 }
154 }
155
156 protected boolean checkDuplicateNames(DDMStructure structure)
157 throws Exception {
158
159 String xml =
160 "<root>" + getFullStructureXML(structure, StringPool.BLANK) +
161 "</root>";
162
163 Document document = SAXReaderUtil.read(xml);
164
165 Set<String> duplicateElementNames =
166 getDuplicateElementNames(
167 document.getRootElement(), new HashSet<String>(),
168 new HashSet<String>());
169
170 if (duplicateElementNames.isEmpty()) {
171 return false;
172 }
173
174 if (!_log.isWarnEnabled()) {
175 return true;
176 }
177
178 StringBundler sb = new StringBundler(
179 duplicateElementNames.size() * 2 + 7);
180
181 sb.append("Structure with class name ID ");
182 sb.append(structure.getClassNameId());
183 sb.append(" and structure key = ");
184 sb.append(structure.getStructureKey());
185 sb.append(" contains more than one element that is identified by the ");
186 sb.append("same name either within itself or within any of its ");
187 sb.append("parent structures. The duplicate element names are: ");
188
189 for (String duplicateElementName : duplicateElementNames) {
190 sb.append(duplicateElementName);
191 sb.append(StringPool.COMMA_AND_SPACE);
192 }
193
194 sb.setIndex(sb.index() - 1);
195
196 _log.warn(sb.toString());
197
198 return true;
199 }
200
201 protected boolean createDefaultMetadataElement(
202 Element dynamicElementElement, String defaultLanguageId) {
203
204 boolean hasDefaultMetadataElement = hasDefaultMetadataElement(
205 dynamicElementElement, defaultLanguageId);
206
207 if (hasDefaultMetadataElement) {
208 return false;
209 }
210
211 Element metadataElement = dynamicElementElement.addElement("meta-data");
212
213 metadataElement.addAttribute("locale", defaultLanguageId);
214
215 Element entryElement = metadataElement.addElement("entry");
216
217 entryElement.addAttribute("name", "label");
218 entryElement.addCDATA(StringPool.BLANK);
219
220 return true;
221 }
222
223 protected ServiceContext createServiceContext() {
224 ServiceContext serviceContext = new ServiceContext();
225
226 serviceContext.setAddGroupPermissions(true);
227 serviceContext.setAddGuestPermissions(true);
228
229 return serviceContext;
230 }
231
232 @Override
233 protected void doVerify() throws Exception {
234 setUpClassNameIds();
235
236 List<DDMStructure> structures =
237 DDMStructureLocalServiceUtil.getStructures();
238
239 for (DDMStructure structure : structures) {
240 if (checkDuplicateNames(structure)) {
241 throw new VerifyException(
242 "Duplicate element name found in structures");
243 }
244 }
245
246 for (DDMStructure structure : structures) {
247 verifyStructure(structure);
248
249 updateFileUploadReferences(structure);
250 }
251 }
252
253 protected Set<String> getDuplicateElementNames(
254 Element element, Set<String> elementNames,
255 Set<String> duplicateElementNames) {
256
257 String elementName = element.attributeValue("name");
258
259 if (!elementNames.add(elementName)) {
260 duplicateElementNames.add(elementName);
261 }
262
263 List<Element> dynamicElements = element.elements("dynamic-element");
264
265 for (Element dynamicElement : dynamicElements) {
266 duplicateElementNames = getDuplicateElementNames(
267 dynamicElement, elementNames, duplicateElementNames);
268 }
269
270 return duplicateElementNames;
271 }
272
273 protected String getFileUploadPath(BaseModel<?> baseModel)
274 throws Exception {
275
276 StringBundler sb = new StringBundler(7);
277
278 long primaryKey = 0;
279
280 String version = StringPool.BLANK;
281
282 if (baseModel instanceof DDLRecordModel) {
283 DDLRecord ddlRecord = (DDLRecord)baseModel;
284
285 primaryKey = ddlRecord.getPrimaryKey();
286
287 DDLRecordVersion ddlRecordVersion = ddlRecord.getRecordVersion();
288
289 version = ddlRecordVersion.getVersion();
290 }
291 else {
292 DLFileEntryMetadata dlFileEntryMetadata =
293 (DLFileEntryMetadata)baseModel;
294
295 primaryKey = dlFileEntryMetadata.getPrimaryKey();
296
297 DLFileVersion dlFileVersion = dlFileEntryMetadata.getFileVersion();
298
299 version = dlFileVersion.getVersion();
300 }
301
302 sb.append("ddm");
303 sb.append(StringPool.SLASH);
304 sb.append(baseModel.getModelClassName());
305 sb.append(StringPool.SLASH);
306 sb.append(primaryKey);
307 sb.append(StringPool.SLASH);
308 sb.append(version);
309
310 return sb.toString();
311 }
312
313 protected String getFullStructureXML(DDMStructure structure, String xml)
314 throws Exception {
315
316 if (structure.getParentStructureId() != 0) {
317 DDMStructure parentStructure =
318 DDMStructureLocalServiceUtil.getStructure(
319 structure.getParentStructureId());
320
321 xml = getFullStructureXML(parentStructure, xml);
322 }
323
324 Document document = SAXReaderUtil.read(structure.getXsd());
325
326 Element rootElement = document.getRootElement();
327
328 List<Element> dynamicElements = rootElement.elements("dynamic-element");
329
330 for (Element dynamicElement : dynamicElements) {
331 xml += dynamicElement.asXML();
332 }
333
334 return xml;
335 }
336
337 protected String getJSON(FileEntry fileEntry) {
338 JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
339
340 jsonObject.put("groupId", fileEntry.getGroupId());
341 jsonObject.put("uuid", fileEntry.getUuid());
342
343 return jsonObject.toString();
344 }
345
346 protected long getUserId(AuditedModel auditedModel) throws Exception {
347 User user = UserLocalServiceUtil.fetchUser(auditedModel.getUserId());
348
349 if (user != null) {
350 return user.getUserId();
351 }
352
353 User defaultUser = UserLocalServiceUtil.getDefaultUser(
354 auditedModel.getCompanyId());
355
356 if (_log.isWarnEnabled()) {
357 _log.warn(
358 "Using default user " + defaultUser.getUserId() +
359 " for audited model " + auditedModel.getModelClassName() +
360 " with primary key " + auditedModel.getPrimaryKeyObj());
361 }
362
363 return defaultUser.getUserId();
364 }
365
366 protected boolean hasDefaultMetadataElement(
367 Element dynamicElementElement, String defaultLanguageId) {
368
369 List<Element> metadataElements = dynamicElementElement.elements(
370 "meta-data");
371
372 for (Element metadataElement : metadataElements) {
373 String languageId = metadataElement.attributeValue("locale");
374
375 if (languageId.equals(defaultLanguageId)) {
376 return true;
377 }
378 }
379
380 return false;
381 }
382
383 protected boolean hasFileUploadFields(DDMStructure structure)
384 throws Exception {
385
386 Map<String, Map<String, String>> fieldsMap = structure.getFieldsMap();
387
388 for (Map<String, String> field : fieldsMap.values()) {
389 String dataType = field.get(FieldConstants.DATA_TYPE);
390
391 if (dataType.equals("file-upload")) {
392 return true;
393 }
394 }
395
396 return false;
397 }
398
399 protected void setUpClassNameIds() {
400 _ddlRecordSetClassNameId = PortalUtil.getClassNameId(
401 DDLRecordSet.class);
402 _ddmStructureClassNameId = PortalUtil.getClassNameId(
403 DDMStructure.class);
404 _dlFileEntryMetadataClassNameId = PortalUtil.getClassNameId(
405 DLFileEntryMetadata.class);
406 }
407
408 protected void updateDDLFileUploadReferences(long ddlRecordSetId)
409 throws Exception {
410
411 List<DDLRecord> ddlRecords = DDLRecordLocalServiceUtil.getRecords(
412 ddlRecordSetId);
413
414 for (DDLRecord ddlRecord : ddlRecords) {
415 updateFileUploadReferences(
416 ddlRecord.getCompanyId(), ddlRecord.getDDMStorageId(),
417 getUserId(ddlRecord), ddlRecord.getGroupId(), ddlRecord,
418 ddlRecord.getStatus());
419 }
420 }
421
422 protected void updateDLFileUploadReferences(long dlFileEntryMetadataId)
423 throws Exception {
424
425 DLFileEntryMetadata dlFileEntryMetadata =
426 DLFileEntryMetadataLocalServiceUtil.getFileEntryMetadata(
427 dlFileEntryMetadataId);
428
429 FileEntry fileEntry = DLAppLocalServiceUtil.getFileEntry(
430 dlFileEntryMetadata.getFileEntryId());
431
432 FileVersion fileVersion = fileEntry.getFileVersion();
433
434 updateFileUploadReferences(
435 fileEntry.getCompanyId(), dlFileEntryMetadata.getDDMStorageId(),
436 getUserId(fileEntry), fileEntry.getGroupId(), dlFileEntryMetadata,
437 fileVersion.getStatus());
438 }
439
440 protected void updateFieldValues(
441 long storageId, Map<String, String> fieldValues)
442 throws Exception {
443
444 Fields fields = new Fields();
445
446 for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
447 Field field = new Field(
448 storageId, entry.getKey(), entry.getValue());
449
450 fields.put(field);
451 }
452
453 ServiceContext serviceContext = new ServiceContext();
454
455 StorageEngineUtil.update(storageId, fields, true, serviceContext);
456 }
457
458 protected void updateFileEntryStatus(
459 FileEntry fileEntry, int status, ServiceContext serviceContext)
460 throws Exception {
461
462 FileVersion fileVersion = fileEntry.getFileVersion();
463
464 Map<String, Serializable> workflowContext =
465 new HashMap<String, Serializable>();
466
467 workflowContext.put("event", DLSyncConstants.EVENT_ADD);
468
469 DLFileEntryLocalServiceUtil.updateStatus(
470 fileVersion.getUserId(), fileVersion.getFileVersionId(), status,
471 workflowContext, serviceContext);
472 }
473
474 protected void updateFileUploadReferences(DDMStructure structure)
475 throws Exception {
476
477 if (!hasFileUploadFields(structure)) {
478 return;
479 }
480
481 List<DDMStructureLink> structureLinks =
482 DDMStructureLinkLocalServiceUtil.getStructureLinks(
483 structure.getStructureId(), QueryUtil.ALL_POS,
484 QueryUtil.ALL_POS);
485
486 for (DDMStructureLink structureLink : structureLinks) {
487 updateFileUploadReferences(structureLink);
488 }
489
490 updateStructure(structure, updateXSD(structure.getXsd()));
491
492 List<DDMTemplate> templates = DDMTemplateLocalServiceUtil.getTemplates(
493 structure.getGroupId(), _ddmStructureClassNameId,
494 structure.getStructureId(),
495 DDMTemplateConstants.TEMPLATE_TYPE_FORM);
496
497 for (DDMTemplate template : templates) {
498 updateTemplate(template, updateXSD(template.getScript()));
499 }
500 }
501
502 protected void updateFileUploadReferences(DDMStructureLink structureLink)
503 throws Exception {
504
505 long classNameId = structureLink.getClassNameId();
506
507 if (classNameId == _ddlRecordSetClassNameId) {
508 updateDDLFileUploadReferences(structureLink.getClassPK());
509 }
510 else if (classNameId == _dlFileEntryMetadataClassNameId) {
511 updateDLFileUploadReferences(structureLink.getClassPK());
512 }
513 }
514
515 protected void updateFileUploadReferences(
516 long companyId, long storageId, long userId, long groupId,
517 BaseModel<?> baseModel, int status)
518 throws Exception {
519
520 Map<String, String> fieldValues = new HashMap<String, String>();
521
522 Fields fields = StorageEngineUtil.getFields(storageId);
523
524 for (Field field : fields) {
525 String dataType = field.getDataType();
526
527 if (!dataType.equals("file-upload") ||
528 Validator.isNull(field.getValue())) {
529
530 continue;
531 }
532
533 long primaryKey = GetterUtil.getLong(baseModel.getPrimaryKeyObj());
534
535 Folder folder = addFolder(
536 userId, groupId, primaryKey, field.getName());
537
538 String valueString = String.valueOf(field.getValue());
539
540 JSONObject jsonObject = JSONFactoryUtil.createJSONObject(
541 valueString);
542
543 String filePath =
544 getFileUploadPath(baseModel) + StringPool.SLASH +
545 field.getName();
546
547 FileEntry fileEntry = addFileEntry(
548 companyId, userId, groupId, folder.getFolderId(),
549 jsonObject.getString("name"), filePath, status);
550
551 if (fileEntry != null) {
552 fieldValues.put(field.getName(), getJSON(fileEntry));
553 }
554 }
555
556 updateFieldValues(storageId, fieldValues);
557 }
558
559 protected void updateStructure(DDMStructure structure, String xsd)
560 throws Exception {
561
562 xsd = DDMXMLUtil.formatXML(xsd);
563
564 structure.setXsd(xsd);
565
566 DDMStructureLocalServiceUtil.updateDDMStructure(structure);
567 }
568
569 protected void updateTemplate(DDMTemplate template, String script)
570 throws Exception {
571
572 script = DDMXMLUtil.formatXML(script);
573
574 template.setScript(script);
575
576 DDMTemplateLocalServiceUtil.updateDDMTemplate(template);
577 }
578
579 protected String updateXSD(String xsd) throws Exception {
580 Document document = SAXReaderUtil.read(xsd);
581
582 Element rootElement = document.getRootElement();
583
584 List<Element> dynamicElementElements = rootElement.elements(
585 "dynamic-element");
586
587 for (Element dynamicElementElement : dynamicElementElements) {
588 updateXSDDynamicElement(dynamicElementElement);
589 }
590
591 return document.asXML();
592 }
593
594 protected void updateXSDDynamicElement(Element element) {
595 String dataType = element.attributeValue("dataType");
596
597 if (Validator.equals(dataType, "file-upload")) {
598 element.addAttribute("dataType", "document-library");
599 element.addAttribute("type", "ddm-documentlibrary");
600 }
601
602 List<Element> dynamicElementElements = element.elements(
603 "dynamic-element");
604
605 for (Element dynamicElementElement : dynamicElementElements) {
606 updateXSDDynamicElement(dynamicElementElement);
607 }
608
609 Attribute attribute = element.attribute("autoGeneratedName");
610
611 if (attribute != null) {
612 element.remove(attribute);
613 }
614 }
615
616 protected void verifyStructure(DDMStructure structure) throws Exception {
617 boolean modified = false;
618
619 String defaultLanguageId = structure.getDefaultLanguageId();
620
621 XPath xPathSelector = SAXReaderUtil.createXPath("
622
623 Document document = structure.getDocument();
624
625 List<Node> nodes = xPathSelector.selectNodes(document);
626
627 for (Node node : nodes) {
628 Element dynamicElementElement = (Element)node;
629
630 updateStructure(structure, updateXSD(structure.getXsd()));
631
632 if (createDefaultMetadataElement(
633 dynamicElementElement, defaultLanguageId)) {
634
635 modified = true;
636 }
637 }
638
639 if (modified) {
640 updateStructure(structure, document.asXML());
641 }
642 }
643
644 private static Log _log = LogFactoryUtil.getLog(
645 VerifyDynamicDataMapping.class);
646
647 private long _ddlRecordSetClassNameId;
648 private long _ddmStructureClassNameId;
649 private long _dlFileEntryMetadataClassNameId;
650
651 }