001
014
015 package com.liferay.portal.verify;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
019 import com.liferay.portal.kernel.dao.orm.Criterion;
020 import com.liferay.portal.kernel.dao.orm.DynamicQuery;
021 import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
022 import com.liferay.portal.kernel.exception.PortalException;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.repository.model.FileEntry;
026 import com.liferay.portal.kernel.repository.model.FileVersion;
027 import com.liferay.portal.kernel.repository.model.Folder;
028 import com.liferay.portal.kernel.util.ContentTypes;
029 import com.liferay.portal.kernel.util.FileUtil;
030 import com.liferay.portal.kernel.util.ListUtil;
031 import com.liferay.portal.kernel.util.LocaleUtil;
032 import com.liferay.portal.kernel.util.MimeTypesUtil;
033 import com.liferay.portal.kernel.util.StreamUtil;
034 import com.liferay.portal.kernel.util.StringBundler;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.StringUtil;
037 import com.liferay.portal.kernel.util.Validator;
038 import com.liferay.portal.kernel.workflow.WorkflowConstants;
039 import com.liferay.portal.repository.liferayrepository.model.LiferayFileEntry;
040 import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
041 import com.liferay.portal.repository.liferayrepository.model.LiferayFolder;
042 import com.liferay.portal.util.PortalInstances;
043 import com.liferay.portal.util.PortalUtil;
044 import com.liferay.portlet.documentlibrary.DuplicateFileException;
045 import com.liferay.portlet.documentlibrary.DuplicateFolderNameException;
046 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
047 import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
048 import com.liferay.portlet.documentlibrary.model.DLFileEntryType;
049 import com.liferay.portlet.documentlibrary.model.DLFileEntryTypeConstants;
050 import com.liferay.portlet.documentlibrary.model.DLFileVersion;
051 import com.liferay.portlet.documentlibrary.model.DLFolder;
052 import com.liferay.portlet.documentlibrary.service.DLAppHelperLocalServiceUtil;
053 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
054 import com.liferay.portlet.documentlibrary.service.DLFileEntryMetadataLocalServiceUtil;
055 import com.liferay.portlet.documentlibrary.service.DLFileEntryTypeLocalServiceUtil;
056 import com.liferay.portlet.documentlibrary.service.DLFileVersionLocalServiceUtil;
057 import com.liferay.portlet.documentlibrary.service.DLFolderLocalServiceUtil;
058 import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
059 import com.liferay.portlet.documentlibrary.util.DLUtil;
060 import com.liferay.portlet.documentlibrary.util.comparator.DLFileVersionVersionComparator;
061 import com.liferay.portlet.documentlibrary.webdav.DLWebDAVStorageImpl;
062 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLinkLocalServiceUtil;
063 import com.liferay.portlet.dynamicdatamapping.storage.StorageAdapter;
064 import com.liferay.portlet.dynamicdatamapping.storage.StorageAdapterRegistryUtil;
065 import com.liferay.portlet.dynamicdatamapping.storage.StorageType;
066
067 import java.io.InputStream;
068
069 import java.util.Collections;
070 import java.util.Date;
071 import java.util.List;
072
073
078 public class VerifyDocumentLibrary extends VerifyProcess {
079
080 protected void addDLFileVersion(DLFileEntry dlFileEntry) {
081 long fileVersionId = CounterLocalServiceUtil.increment();
082
083 DLFileVersion dlFileVersion =
084 DLFileVersionLocalServiceUtil.createDLFileVersion(fileVersionId);
085
086 dlFileVersion.setGroupId(dlFileEntry.getGroupId());
087 dlFileVersion.setCompanyId(dlFileEntry.getCompanyId());
088
089 long userId = dlFileEntry.getUserId();
090
091 dlFileVersion.setUserId(userId);
092
093 String userName = dlFileEntry.getUserName();
094
095 dlFileVersion.setUserName(userName);
096
097 dlFileVersion.setCreateDate(dlFileEntry.getModifiedDate());
098 dlFileVersion.setModifiedDate(dlFileEntry.getModifiedDate());
099 dlFileVersion.setRepositoryId(dlFileEntry.getRepositoryId());
100 dlFileVersion.setFolderId(dlFileEntry.getFolderId());
101 dlFileVersion.setFileEntryId(dlFileEntry.getFileEntryId());
102 dlFileVersion.setExtension(dlFileEntry.getExtension());
103 dlFileVersion.setMimeType(dlFileEntry.getMimeType());
104 dlFileVersion.setTitle(dlFileEntry.getTitle());
105 dlFileVersion.setDescription(dlFileEntry.getDescription());
106 dlFileVersion.setExtraSettings(dlFileEntry.getExtraSettings());
107 dlFileVersion.setFileEntryTypeId(dlFileEntry.getFileEntryTypeId());
108 dlFileVersion.setVersion(dlFileEntry.getVersion());
109 dlFileVersion.setSize(dlFileEntry.getSize());
110 dlFileVersion.setStatus(WorkflowConstants.STATUS_APPROVED);
111 dlFileVersion.setStatusByUserId(userId);
112 dlFileVersion.setStatusByUserName(userName);
113 dlFileVersion.setStatusDate(new Date());
114
115 DLFileVersionLocalServiceUtil.updateDLFileVersion(dlFileVersion);
116 }
117
118 protected void checkDLFileEntryMetadata() throws Exception {
119 List<DLFileEntryMetadata> mismatchedCompanyIdDLFileEntryMetadatas =
120 DLFileEntryMetadataLocalServiceUtil.
121 getMismatchedCompanyIdFileEntryMetadatas();
122
123 if (_log.isDebugEnabled()) {
124 _log.debug(
125 "Deleting " + mismatchedCompanyIdDLFileEntryMetadatas.size() +
126 " file entry metadatas with mismatched company IDs");
127 }
128
129 for (DLFileEntryMetadata dlFileEntryMetadata :
130 mismatchedCompanyIdDLFileEntryMetadatas) {
131
132 deleteUnusedDLFileEntryMetadata(dlFileEntryMetadata);
133 }
134
135 List<DLFileEntryMetadata> noStructuresDLFileEntryMetadatas =
136 DLFileEntryMetadataLocalServiceUtil.
137 getNoStructuresFileEntryMetadatas();
138
139 if (_log.isDebugEnabled()) {
140 _log.debug(
141 "Deleting " + noStructuresDLFileEntryMetadatas.size() +
142 " file entry metadatas with no structures");
143 }
144
145 for (DLFileEntryMetadata dlFileEntryMetadata :
146 noStructuresDLFileEntryMetadatas ) {
147
148 deleteUnusedDLFileEntryMetadata(dlFileEntryMetadata);
149 }
150 }
151
152 protected void checkDLFileEntryType() throws Exception {
153 DLFileEntryType dlFileEntryType =
154 DLFileEntryTypeLocalServiceUtil.fetchDLFileEntryType(
155 DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT);
156
157 if (dlFileEntryType != null) {
158 return;
159 }
160
161 dlFileEntryType = DLFileEntryTypeLocalServiceUtil.createDLFileEntryType(
162 DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT);
163
164 dlFileEntryType.setFileEntryTypeKey(
165 StringUtil.toUpperCase(
166 DLFileEntryTypeConstants.NAME_BASIC_DOCUMENT));
167 dlFileEntryType.setName(
168 DLFileEntryTypeConstants.NAME_BASIC_DOCUMENT,
169 LocaleUtil.getDefault());
170
171 DLFileEntryTypeLocalServiceUtil.updateDLFileEntryType(dlFileEntryType);
172 }
173
174 protected void checkFileVersionMimeTypes(final String[] originalMimeTypes)
175 throws Exception {
176
177 ActionableDynamicQuery actionableDynamicQuery =
178 DLFileVersionLocalServiceUtil.getActionableDynamicQuery();
179
180 actionableDynamicQuery.setAddCriteriaMethod(
181 new ActionableDynamicQuery.AddCriteriaMethod() {
182
183 @Override
184 public void addCriteria(DynamicQuery dynamicQuery) {
185 Criterion criterion = RestrictionsFactoryUtil.eq(
186 "mimeType", originalMimeTypes[0]);
187
188 for (int i = 1; i < originalMimeTypes.length; i++) {
189 criterion = RestrictionsFactoryUtil.or(
190 criterion,
191 RestrictionsFactoryUtil.eq(
192 "mimeType", originalMimeTypes[i]));
193 }
194
195 dynamicQuery.add(criterion);
196 }
197
198 });
199 actionableDynamicQuery.setPerformActionMethod(
200 new ActionableDynamicQuery.PerformActionMethod() {
201
202 @Override
203 public void performAction(Object object) {
204 DLFileVersion dlFileVersion = (DLFileVersion)object;
205
206 InputStream inputStream = null;
207
208 try {
209 inputStream =
210 DLFileEntryLocalServiceUtil.getFileAsStream(
211 dlFileVersion.getFileEntryId(),
212 dlFileVersion.getVersion(), false);
213 }
214 catch (Exception e) {
215 if (_log.isWarnEnabled()) {
216 DLFileEntry dlFileEntry =
217 DLFileEntryLocalServiceUtil.fetchDLFileEntry(
218 dlFileVersion.getFileEntryId());
219
220 if (dlFileEntry == null) {
221 _log.warn(
222 "Unable to find file entry associated " +
223 "with file version " +
224 dlFileVersion.getFileVersionId(),
225 e);
226 }
227 else {
228 StringBundler sb = new StringBundler(4);
229
230 sb.append("Unable to find file version ");
231 sb.append(dlFileVersion.getVersion());
232 sb.append(" for file entry ");
233 sb.append(dlFileEntry.getName());
234
235 _log.warn(sb.toString(), e);
236 }
237 }
238
239 return;
240 }
241
242 String title = DLUtil.getTitleWithExtension(
243 dlFileVersion.getTitle(), dlFileVersion.getExtension());
244
245 String mimeType = getMimeType(inputStream, title);
246
247 if (mimeType.equals(dlFileVersion.getMimeType())) {
248 return;
249 }
250
251 dlFileVersion.setMimeType(mimeType);
252
253 DLFileVersionLocalServiceUtil.updateDLFileVersion(
254 dlFileVersion);
255
256 try {
257 DLFileEntry dlFileEntry = dlFileVersion.getFileEntry();
258
259 if (Validator.equals(
260 dlFileEntry.getVersion(),
261 dlFileVersion.getVersion())) {
262
263 dlFileEntry.setMimeType(mimeType);
264
265 DLFileEntryLocalServiceUtil.updateDLFileEntry(
266 dlFileEntry);
267 }
268 }
269 catch (PortalException e) {
270 if (_log.isWarnEnabled()) {
271 _log.warn(
272 "Unable to get file entry " +
273 dlFileVersion.getFileEntryId(),
274 e);
275 }
276 }
277 }
278
279 });
280
281 if (_log.isDebugEnabled()) {
282 long count = actionableDynamicQuery.performCount();
283
284 _log.debug(
285 "Processing " + count + " file versions with mime types: " +
286 StringUtil.merge(originalMimeTypes, StringPool.COMMA));
287 }
288
289 actionableDynamicQuery.performActions();
290 }
291
292 protected void checkMimeTypes() throws Exception {
293 String[] mimeTypes = {
294 ContentTypes.APPLICATION_OCTET_STREAM,
295 DLWebDAVStorageImpl.MS_OFFICE_2010_TEXT_XML_UTF8
296 };
297
298 checkFileVersionMimeTypes(mimeTypes);
299
300 if (_log.isDebugEnabled()) {
301 _log.debug("Fixed file entries with invalid mime types");
302 }
303 }
304
305 protected void checkMisversionedDLFileEntries() throws Exception {
306 List<DLFileEntry> dlFileEntries =
307 DLFileEntryLocalServiceUtil.getMisversionedFileEntries();
308
309 if (_log.isDebugEnabled()) {
310 _log.debug(
311 "Processing " + dlFileEntries.size() +
312 " misversioned file entries");
313 }
314
315 for (DLFileEntry dlFileEntry : dlFileEntries) {
316 copyDLFileEntry(dlFileEntry);
317
318 addDLFileVersion(dlFileEntry);
319 }
320
321 if (_log.isDebugEnabled()) {
322 _log.debug("Fixed misversioned file entries");
323 }
324 }
325
326 protected void checkTitles() throws Exception {
327 ActionableDynamicQuery actionableDynamicQuery =
328 DLFileEntryLocalServiceUtil.getActionableDynamicQuery();
329
330 actionableDynamicQuery.setPerformActionMethod(
331 new ActionableDynamicQuery.PerformActionMethod() {
332
333 @Override
334 public void performAction(Object object) {
335 DLFileEntry dlFileEntry = (DLFileEntry)object;
336
337 if (dlFileEntry.isInTrash()) {
338 return;
339 }
340
341 String title = dlFileEntry.getTitle();
342
343 if (StringUtil.contains(
344 title, StringPool.DOUBLE_BACK_SLASH)) {
345
346 String newTitle = title.replace(
347 StringPool.BACK_SLASH, StringPool.UNDERLINE);
348
349 try {
350 dlFileEntry = renameTitle(dlFileEntry, newTitle);
351 }
352 catch (Exception e) {
353 if (_log.isWarnEnabled()) {
354 _log.warn(
355 "Unable to rename duplicate title for " +
356 "file entry " +
357 dlFileEntry.getFileEntryId(),
358 e);
359 }
360 }
361 }
362
363 try {
364 DLFileEntryLocalServiceUtil.validateFile(
365 dlFileEntry.getGroupId(), dlFileEntry.getFolderId(),
366 dlFileEntry.getFileEntryId(),
367 dlFileEntry.getFileName(), dlFileEntry.getTitle());
368 }
369 catch (PortalException pe) {
370 if (!(pe instanceof DuplicateFileException) &&
371 !(pe instanceof DuplicateFolderNameException)) {
372
373 return;
374 }
375
376 try {
377 renameDuplicateTitle(dlFileEntry);
378 }
379 catch (Exception e) {
380 if (_log.isWarnEnabled()) {
381 _log.warn(
382 "Unable to rename duplicate title for " +
383 "file entry " +
384 dlFileEntry.getFileEntryId(),
385 e);
386 }
387 }
388 }
389 }
390
391 });
392
393 actionableDynamicQuery.performActions();
394 }
395
396 protected void copyDLFileEntry(DLFileEntry dlFileEntry)
397 throws PortalException {
398
399 long companyId = dlFileEntry.getCompanyId();
400 long dataRepositoryId = dlFileEntry.getDataRepositoryId();
401 String name = dlFileEntry.getName();
402 String version = dlFileEntry.getVersion();
403
404 if (DLStoreUtil.hasFile(companyId, dataRepositoryId, name, version)) {
405 return;
406 }
407
408 List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
409 WorkflowConstants.STATUS_APPROVED);
410
411 if (dlFileVersions.isEmpty()) {
412 dlFileVersions = dlFileEntry.getFileVersions(
413 WorkflowConstants.STATUS_ANY);
414 }
415
416 if (dlFileVersions.isEmpty()) {
417 DLStoreUtil.addFile(companyId, dataRepositoryId, name, new byte[0]);
418
419 return;
420 }
421
422 dlFileVersions = ListUtil.copy(dlFileVersions);
423
424 Collections.sort(dlFileVersions, new DLFileVersionVersionComparator());
425
426 DLFileVersion dlFileVersion = dlFileVersions.get(0);
427
428 DLStoreUtil.copyFileVersion(
429 companyId, dataRepositoryId, name, dlFileVersion.getVersion(),
430 version);
431 }
432
433 protected void deleteOrphanedDLFileEntries() throws Exception {
434 List<DLFileEntry> dlFileEntries =
435 DLFileEntryLocalServiceUtil.getOrphanedFileEntries();
436
437 if (_log.isDebugEnabled()) {
438 _log.debug(
439 "Processing " + dlFileEntries.size() +
440 " file entries with no group");
441 }
442
443 for (DLFileEntry dlFileEntry : dlFileEntries) {
444 try {
445 DLFileEntryLocalServiceUtil.deleteFileEntry(
446 dlFileEntry.getFileEntryId());
447 }
448 catch (Exception e) {
449 if (_log.isWarnEnabled()) {
450 _log.warn(
451 "Unable to remove file entry " +
452 dlFileEntry.getFileEntryId() + ": " +
453 e.getMessage());
454 }
455 }
456 }
457
458 if (_log.isDebugEnabled()) {
459 _log.debug("Removed orphaned file entries");
460 }
461 }
462
463 protected void deleteUnusedDLFileEntryMetadata(
464 DLFileEntryMetadata dlFileEntryMetadata)
465 throws Exception {
466
467 DLFileEntryMetadataLocalServiceUtil.deleteDLFileEntryMetadata(
468 dlFileEntryMetadata);
469
470 StorageAdapter storageAdapter =
471 StorageAdapterRegistryUtil.getStorageAdapter(
472 StorageType.JSON.toString());
473
474 storageAdapter.deleteByClass(dlFileEntryMetadata.getDDMStorageId());
475
476 DDMStructureLinkLocalServiceUtil.deleteStructureLinks(
477 PortalUtil.getClassNameId(DLFileEntryMetadata.class),
478 dlFileEntryMetadata.getFileEntryMetadataId());
479 }
480
481 @Override
482 protected void doVerify() throws Exception {
483 checkMisversionedDLFileEntries();
484
485 checkDLFileEntryType();
486 checkDLFileEntryMetadata();
487 checkMimeTypes();
488 checkTitles();
489 deleteOrphanedDLFileEntries();
490 updateClassNameId();
491 updateFileEntryAssets();
492 updateFolderAssets();
493 verifyTree();
494 }
495
496 protected String getMimeType(InputStream inputStream, String title) {
497 String mimeType = null;
498
499 try {
500 mimeType = MimeTypesUtil.getContentType(inputStream, title);
501 }
502 finally {
503 StreamUtil.cleanUp(inputStream);
504 }
505
506 return mimeType;
507 }
508
509 protected void renameDuplicateTitle(DLFileEntry dlFileEntry)
510 throws PortalException {
511
512 String title = dlFileEntry.getTitle();
513 String titleExtension = StringPool.BLANK;
514 String titleWithoutExtension = dlFileEntry.getTitle();
515
516 if (title.endsWith(
517 StringPool.PERIOD.concat(dlFileEntry.getExtension()))) {
518
519 titleExtension = dlFileEntry.getExtension();
520 titleWithoutExtension = FileUtil.stripExtension(title);
521 }
522
523 for (int i = 1;;) {
524 String uniqueTitle =
525 titleWithoutExtension + StringPool.UNDERLINE +
526 String.valueOf(i);
527
528 if (Validator.isNotNull(titleExtension)) {
529 uniqueTitle = uniqueTitle.concat(
530 StringPool.PERIOD.concat(titleExtension));
531 }
532
533 String uniqueFileName = DLUtil.getSanitizedFileName(
534 uniqueTitle, dlFileEntry.getExtension());
535
536 try {
537 DLFileEntryLocalServiceUtil.validateFile(
538 dlFileEntry.getGroupId(), dlFileEntry.getFolderId(),
539 dlFileEntry.getFileEntryId(), uniqueFileName, uniqueTitle);
540
541 renameTitle(dlFileEntry, uniqueTitle);
542
543 return;
544 }
545 catch (PortalException pe) {
546 if (!(pe instanceof DuplicateFolderNameException) &&
547 !(pe instanceof DuplicateFileException)) {
548
549 throw pe;
550 }
551
552 i++;
553 }
554 }
555 }
556
557 protected DLFileEntry renameTitle(DLFileEntry dlFileEntry, String newTitle)
558 throws PortalException {
559
560 String title = dlFileEntry.getTitle();
561
562 dlFileEntry.setTitle(newTitle);
563
564 String fileName = DLUtil.getSanitizedFileName(
565 newTitle, dlFileEntry.getExtension());
566
567 dlFileEntry.setFileName(fileName);
568
569 DLFileEntry renamedDLFileEntry =
570 DLFileEntryLocalServiceUtil.updateDLFileEntry(dlFileEntry);
571
572 DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
573
574 dlFileVersion.setTitle(newTitle);
575 dlFileVersion.setFileName(fileName);
576
577 DLFileVersionLocalServiceUtil.updateDLFileVersion(dlFileVersion);
578
579 if (_log.isDebugEnabled()) {
580 _log.debug(
581 "Invalid title " + title + " renamed to " + newTitle +
582 " for file entry " + dlFileEntry.getFileEntryId());
583 }
584
585 return renamedDLFileEntry;
586 }
587
588 protected void updateClassNameId() {
589 try {
590 runSQL(
591 "update DLFileEntry set classNameId = 0 where classNameId is " +
592 "null");
593 }
594 catch (Exception e) {
595 if (_log.isWarnEnabled()) {
596 _log.warn(
597 "Unable to fix file entries where class name ID is null",
598 e);
599 }
600 }
601 }
602
603 protected void updateFileEntryAssets() throws Exception {
604 List<DLFileEntry> dlFileEntries =
605 DLFileEntryLocalServiceUtil.getNoAssetFileEntries();
606
607 if (_log.isDebugEnabled()) {
608 _log.debug(
609 "Processing " + dlFileEntries.size() +
610 " file entries with no asset");
611 }
612
613 for (DLFileEntry dlFileEntry : dlFileEntries) {
614 FileEntry fileEntry = new LiferayFileEntry(dlFileEntry);
615 FileVersion fileVersion = new LiferayFileVersion(
616 dlFileEntry.getFileVersion());
617
618 try {
619 DLAppHelperLocalServiceUtil.updateAsset(
620 dlFileEntry.getUserId(), fileEntry, fileVersion, null, null,
621 null);
622 }
623 catch (Exception e) {
624 if (_log.isWarnEnabled()) {
625 _log.warn(
626 "Unable to update asset for file entry " +
627 dlFileEntry.getFileEntryId() + ": " +
628 e.getMessage());
629 }
630 }
631 }
632
633 if (_log.isDebugEnabled()) {
634 _log.debug("Assets verified for file entries");
635 }
636 }
637
638 protected void updateFolderAssets() throws Exception {
639 List<DLFolder> dlFolders = DLFolderLocalServiceUtil.getNoAssetFolders();
640
641 if (_log.isDebugEnabled()) {
642 _log.debug(
643 "Processing " + dlFolders.size() + " folders with no asset");
644 }
645
646 for (DLFolder dlFolder : dlFolders) {
647 Folder folder = new LiferayFolder(dlFolder);
648
649 try {
650 DLAppHelperLocalServiceUtil.updateAsset(
651 dlFolder.getUserId(), folder, null, null, null);
652 }
653 catch (Exception e) {
654 if (_log.isWarnEnabled()) {
655 _log.warn(
656 "Unable to update asset for folder " +
657 dlFolder.getFolderId() + ": " + e.getMessage());
658 }
659 }
660 }
661
662 if (_log.isDebugEnabled()) {
663 _log.debug("Assets verified for folders");
664 }
665 }
666
667 protected void verifyTree() throws Exception {
668 long[] companyIds = PortalInstances.getCompanyIdsBySQL();
669
670 for (long companyId : companyIds) {
671 DLFolderLocalServiceUtil.rebuildTree(companyId);
672 }
673 }
674
675 private static final Log _log = LogFactoryUtil.getLog(
676 VerifyDocumentLibrary.class);
677
678 }