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