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.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.DynamicQueryFactoryUtil;
022    import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
023    import com.liferay.portal.kernel.exception.PortalException;
024    import com.liferay.portal.kernel.exception.SystemException;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.repository.model.FileEntry;
028    import com.liferay.portal.kernel.repository.model.FileVersion;
029    import com.liferay.portal.kernel.repository.model.Folder;
030    import com.liferay.portal.kernel.util.ContentTypes;
031    import com.liferay.portal.kernel.util.ListUtil;
032    import com.liferay.portal.kernel.util.LocaleUtil;
033    import com.liferay.portal.kernel.util.MimeTypesUtil;
034    import com.liferay.portal.kernel.util.StreamUtil;
035    import com.liferay.portal.kernel.util.StringPool;
036    import com.liferay.portal.kernel.util.StringUtil;
037    import com.liferay.portal.kernel.workflow.WorkflowConstants;
038    import com.liferay.portal.repository.liferayrepository.model.LiferayFileEntry;
039    import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
040    import com.liferay.portal.repository.liferayrepository.model.LiferayFolder;
041    import com.liferay.portal.util.PortalInstances;
042    import com.liferay.portlet.documentlibrary.DuplicateFileException;
043    import com.liferay.portlet.documentlibrary.DuplicateFolderNameException;
044    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
045    import com.liferay.portlet.documentlibrary.model.DLFileEntryType;
046    import com.liferay.portlet.documentlibrary.model.DLFileEntryTypeConstants;
047    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
048    import com.liferay.portlet.documentlibrary.model.DLFolder;
049    import com.liferay.portlet.documentlibrary.service.DLAppHelperLocalServiceUtil;
050    import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
051    import com.liferay.portlet.documentlibrary.service.DLFileEntryTypeLocalServiceUtil;
052    import com.liferay.portlet.documentlibrary.service.DLFileVersionLocalServiceUtil;
053    import com.liferay.portlet.documentlibrary.service.DLFolderLocalServiceUtil;
054    import com.liferay.portlet.documentlibrary.service.persistence.DLFileEntryActionableDynamicQuery;
055    import com.liferay.portlet.documentlibrary.service.persistence.DLFileVersionActionableDynamicQuery;
056    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
057    import com.liferay.portlet.documentlibrary.util.DLUtil;
058    import com.liferay.portlet.documentlibrary.util.comparator.FileVersionVersionComparator;
059    import com.liferay.portlet.documentlibrary.webdav.DLWebDAVStorageImpl;
060    import com.liferay.portlet.trash.model.TrashEntry;
061    import com.liferay.portlet.trash.service.TrashEntryLocalServiceUtil;
062    
063    import java.io.InputStream;
064    
065    import java.util.Collections;
066    import java.util.Date;
067    import java.util.List;
068    
069    /**
070     * @author Raymond Aug??
071     * @author Douglas Wong
072     * @author Alexander Chow
073     */
074    public class VerifyDocumentLibrary extends VerifyProcess {
075    
076            protected void addDLFileVersion(DLFileEntry dlFileEntry)
077                    throws SystemException {
078    
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 checkDLFileEntryType() throws Exception {
117                    DLFileEntryType dlFileEntryType =
118                            DLFileEntryTypeLocalServiceUtil.fetchDLFileEntryType(
119                                    DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT);
120    
121                    if (dlFileEntryType != null) {
122                            return;
123                    }
124    
125                    Date now = new Date();
126    
127                    dlFileEntryType = DLFileEntryTypeLocalServiceUtil.createDLFileEntryType(
128                            DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT);
129    
130                    dlFileEntryType.setCreateDate(now);
131                    dlFileEntryType.setModifiedDate(now);
132                    dlFileEntryType.setFileEntryTypeKey(
133                            StringUtil.toUpperCase(
134                                    DLFileEntryTypeConstants.NAME_BASIC_DOCUMENT));
135                    dlFileEntryType.setName(
136                            DLFileEntryTypeConstants.NAME_BASIC_DOCUMENT,
137                            LocaleUtil.getDefault());
138    
139                    DLFileEntryTypeLocalServiceUtil.updateDLFileEntryType(dlFileEntryType);
140            }
141    
142            protected void checkDuplicateTitles() throws Exception {
143                    ActionableDynamicQuery actionableDynamicQuery =
144                            new DLFileEntryActionableDynamicQuery() {
145    
146                                    @Override
147                                    public void performAction(Object object) {
148                                            DLFileEntry dlFileEntry = (DLFileEntry)object;
149    
150                                            if (dlFileEntry.isInTrash()) {
151                                                    return;
152                                            }
153    
154                                            try {
155                                                    DLFileEntryLocalServiceUtil.validateFile(
156                                                            dlFileEntry.getGroupId(), dlFileEntry.getFolderId(),
157                                                            dlFileEntry.getFileEntryId(),
158                                                            dlFileEntry.getTitle(), dlFileEntry.getExtension());
159                                            }
160                                            catch (Exception e1) {
161                                                    if (!(e1 instanceof DuplicateFileException) &&
162                                                            !(e1 instanceof DuplicateFolderNameException)) {
163    
164                                                            return;
165                                                    }
166    
167                                                    try {
168                                                            renameDuplicateTitle(dlFileEntry);
169                                                    }
170                                                    catch (Exception e2) {
171                                                            if (_log.isWarnEnabled()) {
172                                                                    _log.warn(
173                                                                            "Unable to rename duplicate title for " +
174                                                                                    "file entry " +
175                                                                                            dlFileEntry.getFileEntryId() +
176                                                                                                    ": " + e2.getMessage(),
177                                                                            e2);
178                                                            }
179                                                    }
180                                            }
181                                    }
182    
183                            };
184    
185                    actionableDynamicQuery.performActions();
186            }
187    
188            protected void checkFileEntryMimeTypes(final String originalMimeType)
189                    throws Exception {
190    
191                    ActionableDynamicQuery actionableDynamicQuery =
192                            new DLFileEntryActionableDynamicQuery() {
193    
194                            @Override
195                            protected void performAction(Object object)
196                                    throws PortalException, SystemException {
197    
198                                    DLFileEntry dlFileEntry = (DLFileEntry)object;
199    
200                                    InputStream inputStream = null;
201    
202                                    try {
203                                            inputStream = DLFileEntryLocalServiceUtil.getFileAsStream(
204                                                    dlFileEntry.getFileEntryId(), dlFileEntry.getVersion(),
205                                                    false);
206                                    }
207                                    catch (Exception e) {
208                                            if (_log.isWarnEnabled()) {
209                                                    _log.warn(
210                                                            "Unable to find file entry " +
211                                                                    dlFileEntry.getName(),
212                                                            e);
213                                            }
214    
215                                            return;
216                                    }
217    
218                                    String title = DLUtil.getTitleWithExtension(
219                                            dlFileEntry.getTitle(), dlFileEntry.getExtension());
220    
221                                    String mimeType = getMimeType(inputStream, title);
222    
223                                    if (mimeType.equals(originalMimeType)) {
224                                            return;
225                                    }
226    
227                                    dlFileEntry.setMimeType(mimeType);
228    
229                                    DLFileEntryLocalServiceUtil.updateDLFileEntry(dlFileEntry);
230    
231                                    DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
232    
233                                    dlFileVersion.setMimeType(mimeType);
234    
235                                    DLFileVersionLocalServiceUtil.updateDLFileVersion(
236                                            dlFileVersion);
237                            }
238    
239                    };
240    
241                    actionableDynamicQuery.performActions();
242            }
243    
244            protected void checkFileVersionMimeTypes(final String originalMimeType)
245                    throws Exception {
246    
247                    ActionableDynamicQuery actionableDynamicQuery =
248                            new DLFileVersionActionableDynamicQuery() {
249    
250                            @Override
251                            protected void performAction(Object object) throws SystemException {
252                                    DLFileVersion dlFileVersion = (DLFileVersion)object;
253    
254                                    InputStream inputStream = null;
255    
256                                    try {
257                                            inputStream = DLFileEntryLocalServiceUtil.getFileAsStream(
258                                                    dlFileVersion.getFileEntryId(),
259                                                    dlFileVersion.getVersion(), false);
260                                    }
261                                    catch (Exception e) {
262                                            if (_log.isWarnEnabled()) {
263                                                    DLFileEntry dlFileEntry =
264                                                            DLFileEntryLocalServiceUtil.fetchDLFileEntry(
265                                                                    dlFileVersion.getFileEntryId());
266    
267                                                    if (dlFileEntry == null) {
268                                                            _log.warn(
269                                                                    "Unable to find file entry associated with " +
270                                                                            "file version " +
271                                                                                    dlFileVersion.getFileVersionId(),
272                                                                    e);
273                                                    }
274                                                    else {
275                                                            _log.warn(
276                                                                    "Unable to find file version " +
277                                                                            dlFileVersion.getVersion() + " for file " +
278                                                                                    "entry " + dlFileEntry.getName(),
279                                                                    e);
280                                                    }
281                                            }
282    
283                                            return;
284                                    }
285    
286                                    String title = DLUtil.getTitleWithExtension(
287                                            dlFileVersion.getTitle(), dlFileVersion.getExtension());
288    
289                                    String mimeType = getMimeType(inputStream, title);
290    
291                                    if (mimeType.equals(originalMimeType)) {
292                                            return;
293                                    }
294    
295                                    dlFileVersion.setMimeType(mimeType);
296    
297                                    DLFileVersionLocalServiceUtil.updateDLFileVersion(
298                                            dlFileVersion);
299                            }
300    
301                    };
302    
303                    actionableDynamicQuery.performActions();
304            }
305    
306            protected void checkMimeTypes() throws Exception {
307                    String[] mimeTypes = {
308                            ContentTypes.APPLICATION_OCTET_STREAM,
309                            DLWebDAVStorageImpl.MS_OFFICE_2010_TEXT_XML_UTF8
310                    };
311    
312                    for (String mimeType : mimeTypes) {
313                            checkFileEntryMimeTypes(mimeType);
314                            checkFileVersionMimeTypes(mimeType);
315                    }
316    
317                    if (_log.isDebugEnabled()) {
318                            _log.debug("Fixed file entries with invalid mime types");
319                    }
320            }
321    
322            protected void checkMisversionedDLFileEntries() throws Exception {
323                    List<DLFileEntry> dlFileEntries =
324                            DLFileEntryLocalServiceUtil.getMisversionedFileEntries();
325    
326                    if (_log.isDebugEnabled()) {
327                            _log.debug(
328                                    "Processing " + dlFileEntries.size() +
329                                            " misversioned file entries");
330                    }
331    
332                    for (DLFileEntry dlFileEntry : dlFileEntries) {
333                            copyDLFileEntry(dlFileEntry);
334    
335                            addDLFileVersion(dlFileEntry);
336                    }
337    
338                    if (_log.isDebugEnabled()) {
339                            _log.debug("Fixed misversioned file entries");
340                    }
341            }
342    
343            protected void checkTitles() throws Exception {
344                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
345                            DLFileEntry.class);
346    
347                    Criterion criterion1 = RestrictionsFactoryUtil.like("title", "%/%");
348                    Criterion criterion2 = RestrictionsFactoryUtil.like("title", "%\\\\%");
349    
350                    dynamicQuery.add(RestrictionsFactoryUtil.or(criterion1, criterion2));
351    
352                    List<DLFileEntry> dlFileEntries =
353                            DLFileEntryLocalServiceUtil.dynamicQuery(dynamicQuery);
354    
355                    for (DLFileEntry dlFileEntry : dlFileEntries) {
356                            TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
357                                    dlFileEntry.getModelClassName(), dlFileEntry.getFileEntryId());
358    
359                            if (trashEntry != null) {
360                                    continue;
361                            }
362    
363                            String title = dlFileEntry.getTitle();
364    
365                            String newTitle = title.replace(StringPool.SLASH, StringPool.BLANK);
366    
367                            newTitle = newTitle.replace(
368                                    StringPool.BACK_SLASH, StringPool.UNDERLINE);
369    
370                            renameTitle(dlFileEntry, newTitle);
371                    }
372    
373                    checkDuplicateTitles();
374            }
375    
376            protected void copyDLFileEntry(DLFileEntry dlFileEntry)
377                    throws PortalException, SystemException {
378    
379                    long companyId = dlFileEntry.getCompanyId();
380                    long dataRepositoryId = dlFileEntry.getDataRepositoryId();
381                    String name = dlFileEntry.getName();
382                    String version = dlFileEntry.getVersion();
383    
384                    if (DLStoreUtil.hasFile(companyId, dataRepositoryId, name, version)) {
385                            return;
386                    }
387    
388                    FileVersionVersionComparator comparator =
389                            new FileVersionVersionComparator();
390    
391                    List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
392                            WorkflowConstants.STATUS_APPROVED);
393    
394                    if (dlFileVersions.isEmpty()) {
395                            dlFileVersions = dlFileEntry.getFileVersions(
396                                    WorkflowConstants.STATUS_ANY);
397                    }
398    
399                    if (dlFileVersions.isEmpty()) {
400                            DLStoreUtil.addFile(companyId, dataRepositoryId, name, new byte[0]);
401    
402                            return;
403                    }
404    
405                    dlFileVersions = ListUtil.copy(dlFileVersions);
406    
407                    Collections.sort(dlFileVersions, comparator);
408    
409                    DLFileVersion dlFileVersion = dlFileVersions.get(0);
410    
411                    DLStoreUtil.copyFileVersion(
412                            companyId, dataRepositoryId, name, dlFileVersion.getVersion(),
413                            version);
414            }
415    
416            @Override
417            protected void doVerify() throws Exception {
418                    checkMisversionedDLFileEntries();
419    
420                    checkDLFileEntryType();
421                    checkMimeTypes();
422                    checkTitles();
423                    removeOrphanedDLFileEntries();
424                    updateClassNameId();
425                    updateFileEntryAssets();
426                    updateFolderAssets();
427                    verifyTree();
428            }
429    
430            protected String getMimeType(InputStream inputStream, String title) {
431                    String mimeType = null;
432    
433                    try {
434                            mimeType = MimeTypesUtil.getContentType(inputStream, title);
435                    }
436                    finally {
437                            StreamUtil.cleanUp(inputStream);
438                    }
439    
440                    return mimeType;
441            }
442    
443            protected void updateClassNameId() {
444                    try {
445                            runSQL(
446                                    "update DLFileEntry set classNameId = 0 where classNameId is " +
447                                            "null");
448                    }
449                    catch (Exception e) {
450                            if (_log.isWarnEnabled()) {
451                                    _log.warn(
452                                            "Unable to fix file entries where class name ID is null",
453                                            e);
454                            }
455                    }
456            }
457    
458            protected void removeOrphanedDLFileEntries() throws Exception {
459                    List<DLFileEntry> dlFileEntries =
460                            DLFileEntryLocalServiceUtil.getOrphanedFileEntries();
461    
462                    if (_log.isDebugEnabled()) {
463                            _log.debug(
464                                    "Processing " + dlFileEntries.size() +
465                                            " file entries with no group");
466                    }
467    
468                    for (DLFileEntry dlFileEntry : dlFileEntries) {
469                            try {
470                                    DLFileEntryLocalServiceUtil.deleteFileEntry(
471                                            dlFileEntry.getFileEntryId());
472                            }
473                            catch (Exception e) {
474                                    if (_log.isWarnEnabled()) {
475                                            _log.warn(
476                                                    "Unable to remove file entry " +
477                                                            dlFileEntry.getFileEntryId() + ": " +
478                                                                    e.getMessage());
479                                    }
480                            }
481                    }
482    
483                    if (_log.isDebugEnabled()) {
484                            _log.debug("Removed orphaned file entries");
485                    }
486            }
487    
488            protected void renameDuplicateTitle(DLFileEntry dlFileEntry)
489                    throws PortalException, SystemException {
490    
491                    String uniqueTitle = DLFileEntryLocalServiceUtil.getUniqueTitle(
492                            dlFileEntry.getGroupId(), dlFileEntry.getFolderId(),
493                            dlFileEntry.getFileEntryId(), dlFileEntry.getTitle(),
494                            dlFileEntry.getExtension());
495    
496                    renameTitle(dlFileEntry, uniqueTitle);
497            }
498    
499            protected void renameTitle(DLFileEntry dlFileEntry, String newTitle)
500                    throws PortalException, SystemException {
501    
502                    String title = dlFileEntry.getTitle();
503    
504                    dlFileEntry.setTitle(newTitle);
505    
506                    DLFileEntryLocalServiceUtil.updateDLFileEntry(dlFileEntry);
507    
508                    DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
509    
510                    dlFileVersion.setTitle(newTitle);
511    
512                    DLFileVersionLocalServiceUtil.updateDLFileVersion(dlFileVersion);
513    
514                    if (_log.isDebugEnabled()) {
515                            _log.debug(
516                                    "Invalid title " + title + " renamed to " + newTitle +
517                                            " for file entry " + dlFileEntry.getFileEntryId());
518                    }
519            }
520    
521            protected void updateFileEntryAssets() throws Exception {
522                    List<DLFileEntry> dlFileEntries =
523                            DLFileEntryLocalServiceUtil.getNoAssetFileEntries();
524    
525                    if (_log.isDebugEnabled()) {
526                            _log.debug(
527                                    "Processing " + dlFileEntries.size() +
528                                            " file entries with no asset");
529                    }
530    
531                    for (DLFileEntry dlFileEntry : dlFileEntries) {
532                            FileEntry fileEntry = new LiferayFileEntry(dlFileEntry);
533                            FileVersion fileVersion = new LiferayFileVersion(
534                                    dlFileEntry.getFileVersion());
535    
536                            try {
537                                    DLAppHelperLocalServiceUtil.updateAsset(
538                                            dlFileEntry.getUserId(), fileEntry, fileVersion, null, null,
539                                            null);
540                            }
541                            catch (Exception e) {
542                                    if (_log.isWarnEnabled()) {
543                                            _log.warn(
544                                                    "Unable to update asset for file entry " +
545                                                            dlFileEntry.getFileEntryId() + ": " +
546                                                                    e.getMessage());
547                                    }
548                            }
549                    }
550    
551                    if (_log.isDebugEnabled()) {
552                            _log.debug("Assets verified for file entries");
553                    }
554            }
555    
556            protected void updateFolderAssets() throws Exception {
557                    List<DLFolder> dlFolders = DLFolderLocalServiceUtil.getNoAssetFolders();
558    
559                    if (_log.isDebugEnabled()) {
560                            _log.debug(
561                                    "Processing " + dlFolders.size() + " folders with no asset");
562                    }
563    
564                    for (DLFolder dlFolder : dlFolders) {
565                            Folder folder = new LiferayFolder(dlFolder);
566    
567                            try {
568                                    DLAppHelperLocalServiceUtil.updateAsset(
569                                            dlFolder.getUserId(), folder, null, null, null);
570                            }
571                            catch (Exception e) {
572                                    if (_log.isWarnEnabled()) {
573                                            _log.warn(
574                                                    "Unable to update asset for folder " +
575                                                            dlFolder.getFolderId() + ": " + e.getMessage());
576                                    }
577                            }
578                    }
579    
580                    if (_log.isDebugEnabled()) {
581                            _log.debug("Assets verified for folders");
582                    }
583            }
584    
585            protected void verifyTree() throws Exception {
586                    long[] companyIds = PortalInstances.getCompanyIdsBySQL();
587    
588                    for (long companyId : companyIds) {
589                            DLFolderLocalServiceUtil.rebuildTree(companyId);
590                    }
591            }
592    
593            private static Log _log = LogFactoryUtil.getLog(
594                    VerifyDocumentLibrary.class);
595    
596    }