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