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