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.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.FileUtil;
032    import com.liferay.portal.kernel.util.ListUtil;
033    import com.liferay.portal.kernel.util.LocaleUtil;
034    import com.liferay.portal.kernel.util.MimeTypesUtil;
035    import com.liferay.portal.kernel.util.StreamUtil;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.Validator;
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                            protected void performAction(Object object)
198                                    throws PortalException, SystemException {
199    
200                                    DLFileEntry dlFileEntry = (DLFileEntry)object;
201    
202                                    InputStream inputStream = null;
203    
204                                    try {
205                                            inputStream = DLFileEntryLocalServiceUtil.getFileAsStream(
206                                                    dlFileEntry.getFileEntryId(), dlFileEntry.getVersion(),
207                                                    false);
208                                    }
209                                    catch (Exception e) {
210                                            if (_log.isWarnEnabled()) {
211                                                    _log.warn(
212                                                            "Unable to find file entry " +
213                                                                    dlFileEntry.getName(),
214                                                            e);
215                                            }
216    
217                                            return;
218                                    }
219    
220                                    String title = DLUtil.getTitleWithExtension(
221                                            dlFileEntry.getTitle(), dlFileEntry.getExtension());
222    
223                                    String mimeType = getMimeType(inputStream, title);
224    
225                                    if (mimeType.equals(originalMimeType)) {
226                                            return;
227                                    }
228    
229                                    dlFileEntry.setMimeType(mimeType);
230    
231                                    DLFileEntryLocalServiceUtil.updateDLFileEntry(dlFileEntry);
232    
233                                    DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
234    
235                                    dlFileVersion.setMimeType(mimeType);
236    
237                                    DLFileVersionLocalServiceUtil.updateDLFileVersion(
238                                            dlFileVersion);
239                            }
240    
241                    };
242    
243                    actionableDynamicQuery.performActions();
244            }
245    
246            protected void checkFileVersionMimeTypes(final String originalMimeType)
247                    throws Exception {
248    
249                    ActionableDynamicQuery actionableDynamicQuery =
250                            new DLFileVersionActionableDynamicQuery() {
251    
252                            @Override
253                            protected void performAction(Object object) throws SystemException {
254                                    DLFileVersion dlFileVersion = (DLFileVersion)object;
255    
256                                    InputStream inputStream = null;
257    
258                                    try {
259                                            inputStream = DLFileEntryLocalServiceUtil.getFileAsStream(
260                                                    dlFileVersion.getFileEntryId(),
261                                                    dlFileVersion.getVersion(), false);
262                                    }
263                                    catch (Exception e) {
264                                            if (_log.isWarnEnabled()) {
265                                                    DLFileEntry dlFileEntry =
266                                                            DLFileEntryLocalServiceUtil.fetchDLFileEntry(
267                                                                    dlFileVersion.getFileEntryId());
268    
269                                                    if (dlFileEntry == null) {
270                                                            _log.warn(
271                                                                    "Unable to find file entry associated with " +
272                                                                            "file version " +
273                                                                                    dlFileVersion.getFileVersionId(),
274                                                                    e);
275                                                    }
276                                                    else {
277                                                            _log.warn(
278                                                                    "Unable to find file version " +
279                                                                            dlFileVersion.getVersion() + " for file " +
280                                                                                    "entry " + dlFileEntry.getName(),
281                                                                    e);
282                                                    }
283                                            }
284    
285                                            return;
286                                    }
287    
288                                    String title = DLUtil.getTitleWithExtension(
289                                            dlFileVersion.getTitle(), dlFileVersion.getExtension());
290    
291                                    String mimeType = getMimeType(inputStream, title);
292    
293                                    if (mimeType.equals(originalMimeType)) {
294                                            return;
295                                    }
296    
297                                    dlFileVersion.setMimeType(mimeType);
298    
299                                    DLFileVersionLocalServiceUtil.updateDLFileVersion(
300                                            dlFileVersion);
301                            }
302    
303                    };
304    
305                    actionableDynamicQuery.performActions();
306            }
307    
308            protected void checkMimeTypes() throws Exception {
309                    String[] mimeTypes = {
310                            ContentTypes.APPLICATION_OCTET_STREAM,
311                            DLWebDAVStorageImpl.MS_OFFICE_2010_TEXT_XML_UTF8
312                    };
313    
314                    for (String mimeType : mimeTypes) {
315                            checkFileEntryMimeTypes(mimeType);
316                            checkFileVersionMimeTypes(mimeType);
317                    }
318    
319                    if (_log.isDebugEnabled()) {
320                            _log.debug("Fixed file entries with invalid mime types");
321                    }
322            }
323    
324            protected void checkMisversionedDLFileEntries() throws Exception {
325                    List<DLFileEntry> dlFileEntries =
326                            DLFileEntryLocalServiceUtil.getMisversionedFileEntries();
327    
328                    if (_log.isDebugEnabled()) {
329                            _log.debug(
330                                    "Processing " + dlFileEntries.size() +
331                                            " misversioned file entries");
332                    }
333    
334                    for (DLFileEntry dlFileEntry : dlFileEntries) {
335                            copyDLFileEntry(dlFileEntry);
336    
337                            addDLFileVersion(dlFileEntry);
338                    }
339    
340                    if (_log.isDebugEnabled()) {
341                            _log.debug("Fixed misversioned file entries");
342                    }
343            }
344    
345            protected void checkTitles() throws Exception {
346                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
347                            DLFileEntry.class);
348    
349                    Criterion criterion1 = RestrictionsFactoryUtil.like("title", "%/%");
350                    Criterion criterion2 = RestrictionsFactoryUtil.like("title", "%\\\\%");
351    
352                    dynamicQuery.add(RestrictionsFactoryUtil.or(criterion1, criterion2));
353    
354                    List<DLFileEntry> dlFileEntries =
355                            DLFileEntryLocalServiceUtil.dynamicQuery(dynamicQuery);
356    
357                    for (DLFileEntry dlFileEntry : dlFileEntries) {
358                            TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
359                                    dlFileEntry.getModelClassName(), dlFileEntry.getFileEntryId());
360    
361                            if (trashEntry != null) {
362                                    continue;
363                            }
364    
365                            String title = dlFileEntry.getTitle();
366    
367                            String newTitle = title.replace(StringPool.SLASH, StringPool.BLANK);
368    
369                            newTitle = newTitle.replace(
370                                    StringPool.BACK_SLASH, StringPool.UNDERLINE);
371    
372                            renameTitle(dlFileEntry, newTitle);
373                    }
374    
375                    checkDuplicateTitles();
376            }
377    
378            protected void copyDLFileEntry(DLFileEntry dlFileEntry)
379                    throws PortalException, SystemException {
380    
381                    long companyId = dlFileEntry.getCompanyId();
382                    long dataRepositoryId = dlFileEntry.getDataRepositoryId();
383                    String name = dlFileEntry.getName();
384                    String version = dlFileEntry.getVersion();
385    
386                    if (DLStoreUtil.hasFile(companyId, dataRepositoryId, name, version)) {
387                            return;
388                    }
389    
390                    FileVersionVersionComparator comparator =
391                            new FileVersionVersionComparator();
392    
393                    List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
394                            WorkflowConstants.STATUS_APPROVED);
395    
396                    if (dlFileVersions.isEmpty()) {
397                            dlFileVersions = dlFileEntry.getFileVersions(
398                                    WorkflowConstants.STATUS_ANY);
399                    }
400    
401                    if (dlFileVersions.isEmpty()) {
402                            DLStoreUtil.addFile(companyId, dataRepositoryId, name, new byte[0]);
403    
404                            return;
405                    }
406    
407                    dlFileVersions = ListUtil.copy(dlFileVersions);
408    
409                    Collections.sort(dlFileVersions, comparator);
410    
411                    DLFileVersion dlFileVersion = dlFileVersions.get(0);
412    
413                    DLStoreUtil.copyFileVersion(
414                            companyId, dataRepositoryId, name, dlFileVersion.getVersion(),
415                            version);
416            }
417    
418            @Override
419            protected void doVerify() throws Exception {
420                    checkMisversionedDLFileEntries();
421    
422                    checkDLFileEntryType();
423                    checkMimeTypes();
424                    checkTitles();
425                    removeOrphanedDLFileEntries();
426                    updateClassNameId();
427                    updateFileEntryAssets();
428                    updateFolderAssets();
429                    verifyTree();
430            }
431    
432            protected String getMimeType(InputStream inputStream, String title) {
433                    String mimeType = null;
434    
435                    try {
436                            mimeType = MimeTypesUtil.getContentType(inputStream, title);
437                    }
438                    finally {
439                            StreamUtil.cleanUp(inputStream);
440                    }
441    
442                    return mimeType;
443            }
444    
445            protected void updateClassNameId() {
446                    try {
447                            runSQL(
448                                    "update DLFileEntry set classNameId = 0 where classNameId is " +
449                                            "null");
450                    }
451                    catch (Exception e) {
452                            if (_log.isWarnEnabled()) {
453                                    _log.warn(
454                                            "Unable to fix file entries where class name ID is null",
455                                            e);
456                            }
457                    }
458            }
459    
460            protected void removeOrphanedDLFileEntries() throws Exception {
461                    List<DLFileEntry> dlFileEntries =
462                            DLFileEntryLocalServiceUtil.getOrphanedFileEntries();
463    
464                    if (_log.isDebugEnabled()) {
465                            _log.debug(
466                                    "Processing " + dlFileEntries.size() +
467                                            " file entries with no group");
468                    }
469    
470                    for (DLFileEntry dlFileEntry : dlFileEntries) {
471                            try {
472                                    DLFileEntryLocalServiceUtil.deleteFileEntry(
473                                            dlFileEntry.getFileEntryId());
474                            }
475                            catch (Exception e) {
476                                    if (_log.isWarnEnabled()) {
477                                            _log.warn(
478                                                    "Unable to remove file entry " +
479                                                            dlFileEntry.getFileEntryId() + ": " +
480                                                                    e.getMessage());
481                                    }
482                            }
483                    }
484    
485                    if (_log.isDebugEnabled()) {
486                            _log.debug("Removed orphaned file entries");
487                    }
488            }
489    
490            protected void renameDuplicateTitle(DLFileEntry dlFileEntry)
491                    throws PortalException, SystemException {
492    
493                    String title = dlFileEntry.getTitle();
494                    String titleExtension = StringPool.BLANK;
495                    String titleWithoutExtension = dlFileEntry.getTitle();
496    
497                    if (title.endsWith(
498                                    StringPool.PERIOD.concat(dlFileEntry.getExtension()))) {
499    
500                            titleExtension = dlFileEntry.getExtension();
501                            titleWithoutExtension = FileUtil.stripExtension(title);
502                    }
503    
504                    for (int i = 1;;) {
505                            String uniqueTitle =
506                                    titleWithoutExtension + StringPool.UNDERLINE +
507                                            String.valueOf(i);
508    
509                            if (Validator.isNotNull(titleExtension)) {
510                                    uniqueTitle = uniqueTitle.concat(
511                                            StringPool.PERIOD.concat(titleExtension));
512                            }
513    
514                            try {
515                                    DLFileEntryLocalServiceUtil.validateFile(
516                                            dlFileEntry.getGroupId(), dlFileEntry.getFolderId(),
517                                            dlFileEntry.getFileEntryId(), uniqueTitle,
518                                            dlFileEntry.getExtension());
519    
520                                    renameTitle(dlFileEntry, uniqueTitle);
521    
522                                    return;
523                            }
524                            catch (PortalException pe) {
525                                    if (!(pe instanceof DuplicateFolderNameException) &&
526                                             !(pe instanceof DuplicateFileException)) {
527    
528                                            throw pe;
529                                    }
530    
531                                    i++;
532                            }
533                    }
534            }
535    
536            protected void renameTitle(DLFileEntry dlFileEntry, String newTitle)
537                    throws PortalException, SystemException {
538    
539                    String title = dlFileEntry.getTitle();
540    
541                    dlFileEntry.setTitle(newTitle);
542    
543                    DLFileEntryLocalServiceUtil.updateDLFileEntry(dlFileEntry);
544    
545                    DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
546    
547                    dlFileVersion.setTitle(newTitle);
548    
549                    DLFileVersionLocalServiceUtil.updateDLFileVersion(dlFileVersion);
550    
551                    if (_log.isDebugEnabled()) {
552                            _log.debug(
553                                    "Invalid title " + title + " renamed to " + newTitle +
554                                            " for file entry " + dlFileEntry.getFileEntryId());
555                    }
556            }
557    
558            protected void updateFileEntryAssets() throws Exception {
559                    List<DLFileEntry> dlFileEntries =
560                            DLFileEntryLocalServiceUtil.getNoAssetFileEntries();
561    
562                    if (_log.isDebugEnabled()) {
563                            _log.debug(
564                                    "Processing " + dlFileEntries.size() +
565                                            " file entries with no asset");
566                    }
567    
568                    for (DLFileEntry dlFileEntry : dlFileEntries) {
569                            FileEntry fileEntry = new LiferayFileEntry(dlFileEntry);
570                            FileVersion fileVersion = new LiferayFileVersion(
571                                    dlFileEntry.getFileVersion());
572    
573                            try {
574                                    DLAppHelperLocalServiceUtil.updateAsset(
575                                            dlFileEntry.getUserId(), fileEntry, fileVersion, null, null,
576                                            null);
577                            }
578                            catch (Exception e) {
579                                    if (_log.isWarnEnabled()) {
580                                            _log.warn(
581                                                    "Unable to update asset for file entry " +
582                                                            dlFileEntry.getFileEntryId() + ": " +
583                                                                    e.getMessage());
584                                    }
585                            }
586                    }
587    
588                    if (_log.isDebugEnabled()) {
589                            _log.debug("Assets verified for file entries");
590                    }
591            }
592    
593            protected void updateFolderAssets() throws Exception {
594                    List<DLFolder> dlFolders = DLFolderLocalServiceUtil.getNoAssetFolders();
595    
596                    if (_log.isDebugEnabled()) {
597                            _log.debug(
598                                    "Processing " + dlFolders.size() + " folders with no asset");
599                    }
600    
601                    for (DLFolder dlFolder : dlFolders) {
602                            Folder folder = new LiferayFolder(dlFolder);
603    
604                            try {
605                                    DLAppHelperLocalServiceUtil.updateAsset(
606                                            dlFolder.getUserId(), folder, null, null, null);
607                            }
608                            catch (Exception e) {
609                                    if (_log.isWarnEnabled()) {
610                                            _log.warn(
611                                                    "Unable to update asset for folder " +
612                                                            dlFolder.getFolderId() + ": " + e.getMessage());
613                                    }
614                            }
615                    }
616    
617                    if (_log.isDebugEnabled()) {
618                            _log.debug("Assets verified for folders");
619                    }
620            }
621    
622            protected void verifyTree() throws Exception {
623                    long[] companyIds = PortalInstances.getCompanyIdsBySQL();
624    
625                    for (long companyId : companyIds) {
626                            DLFolderLocalServiceUtil.rebuildTree(companyId);
627                    }
628            }
629    
630            private static Log _log = LogFactoryUtil.getLog(
631                    VerifyDocumentLibrary.class);
632    
633    }