001    /**
002     * Copyright (c) 2000-present 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.portlet.documentlibrary.util;
016    
017    import com.liferay.document.library.kernel.model.DLFileEntryConstants;
018    import com.liferay.document.library.kernel.model.DLFileEntryType;
019    import com.liferay.document.library.kernel.model.DLFileEntryTypeConstants;
020    import com.liferay.document.library.kernel.model.DLFileShortcut;
021    import com.liferay.document.library.kernel.model.DLFileVersion;
022    import com.liferay.document.library.kernel.model.DLFolder;
023    import com.liferay.document.library.kernel.model.DLFolderConstants;
024    import com.liferay.document.library.kernel.service.DLAppLocalServiceUtil;
025    import com.liferay.document.library.kernel.service.DLFolderLocalServiceUtil;
026    import com.liferay.document.library.kernel.util.DL;
027    import com.liferay.document.library.kernel.util.ImageProcessorUtil;
028    import com.liferay.document.library.kernel.util.PDFProcessorUtil;
029    import com.liferay.document.library.kernel.util.VideoProcessorUtil;
030    import com.liferay.document.library.kernel.util.comparator.RepositoryModelCreateDateComparator;
031    import com.liferay.document.library.kernel.util.comparator.RepositoryModelModifiedDateComparator;
032    import com.liferay.document.library.kernel.util.comparator.RepositoryModelReadCountComparator;
033    import com.liferay.document.library.kernel.util.comparator.RepositoryModelSizeComparator;
034    import com.liferay.document.library.kernel.util.comparator.RepositoryModelTitleComparator;
035    import com.liferay.portal.kernel.configuration.Filter;
036    import com.liferay.portal.kernel.exception.PortalException;
037    import com.liferay.portal.kernel.language.LanguageUtil;
038    import com.liferay.portal.kernel.log.Log;
039    import com.liferay.portal.kernel.log.LogFactoryUtil;
040    import com.liferay.portal.kernel.model.Company;
041    import com.liferay.portal.kernel.model.Group;
042    import com.liferay.portal.kernel.model.LayoutConstants;
043    import com.liferay.portal.kernel.model.Subscription;
044    import com.liferay.portal.kernel.portlet.PortletLayoutFinder;
045    import com.liferay.portal.kernel.portlet.PortletProvider;
046    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
047    import com.liferay.portal.kernel.portlet.PortletURLFactoryUtil;
048    import com.liferay.portal.kernel.repository.model.FileEntry;
049    import com.liferay.portal.kernel.repository.model.FileVersion;
050    import com.liferay.portal.kernel.repository.model.Folder;
051    import com.liferay.portal.kernel.search.Document;
052    import com.liferay.portal.kernel.search.Field;
053    import com.liferay.portal.kernel.search.Hits;
054    import com.liferay.portal.kernel.service.GroupLocalServiceUtil;
055    import com.liferay.portal.kernel.service.ServiceContext;
056    import com.liferay.portal.kernel.service.SubscriptionLocalServiceUtil;
057    import com.liferay.portal.kernel.service.WorkflowDefinitionLinkLocalServiceUtil;
058    import com.liferay.portal.kernel.theme.PortletDisplay;
059    import com.liferay.portal.kernel.theme.ThemeDisplay;
060    import com.liferay.portal.kernel.util.ArrayUtil;
061    import com.liferay.portal.kernel.util.CharPool;
062    import com.liferay.portal.kernel.util.Constants;
063    import com.liferay.portal.kernel.util.FileUtil;
064    import com.liferay.portal.kernel.util.GetterUtil;
065    import com.liferay.portal.kernel.util.HtmlUtil;
066    import com.liferay.portal.kernel.util.HttpUtil;
067    import com.liferay.portal.kernel.util.OrderByComparator;
068    import com.liferay.portal.kernel.util.PortalUtil;
069    import com.liferay.portal.kernel.util.PrefsPropsUtil;
070    import com.liferay.portal.kernel.util.PropsKeys;
071    import com.liferay.portal.kernel.util.PropsUtil;
072    import com.liferay.portal.kernel.util.SetUtil;
073    import com.liferay.portal.kernel.util.StringBundler;
074    import com.liferay.portal.kernel.util.StringPool;
075    import com.liferay.portal.kernel.util.StringUtil;
076    import com.liferay.portal.kernel.util.Validator;
077    import com.liferay.portal.kernel.util.WebKeys;
078    import com.liferay.portal.kernel.workflow.WorkflowConstants;
079    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
080    import com.liferay.portal.util.PropsValues;
081    import com.liferay.portlet.documentlibrary.webdav.DLWebDAVUtil;
082    import com.liferay.registry.collections.ServiceTrackerCollections;
083    import com.liferay.registry.collections.ServiceTrackerList;
084    import com.liferay.trash.kernel.util.TrashUtil;
085    
086    import java.io.Serializable;
087    
088    import java.util.ArrayList;
089    import java.util.Collections;
090    import java.util.Date;
091    import java.util.HashMap;
092    import java.util.HashSet;
093    import java.util.LinkedHashMap;
094    import java.util.List;
095    import java.util.Map;
096    import java.util.Objects;
097    import java.util.Set;
098    import java.util.TreeSet;
099    
100    import javax.portlet.PortletRequest;
101    import javax.portlet.PortletURL;
102    
103    import javax.servlet.http.HttpServletRequest;
104    
105    /**
106     * @author Brian Wing Shun Chan
107     * @author Julio Camarero
108     */
109    public class DLImpl implements DL {
110    
111            @Override
112            public int compareVersions(String version1, String version2) {
113                    int[] splitVersion1 = StringUtil.split(version1, StringPool.PERIOD, 0);
114                    int[] splitVersion2 = StringUtil.split(version2, StringPool.PERIOD, 0);
115    
116                    if ((splitVersion1.length != 2) && (splitVersion2.length != 2)) {
117                            return 0;
118                    }
119                    else if (splitVersion1.length != 2) {
120                            return -1;
121                    }
122                    else if (splitVersion2.length != 2) {
123                            return 1;
124                    }
125    
126                    if (splitVersion1[0] > splitVersion2[0]) {
127                            return 1;
128                    }
129                    else if (splitVersion1[0] < splitVersion2[0]) {
130                            return -1;
131                    }
132                    else if (splitVersion1[1] > splitVersion2[1]) {
133                            return 1;
134                    }
135                    else if (splitVersion1[1] < splitVersion2[1]) {
136                            return -1;
137                    }
138    
139                    return 0;
140            }
141    
142            public void destroy() {
143                    _serviceTrackerList.close();
144            }
145    
146            @Override
147            public String getAbsolutePath(PortletRequest portletRequest, long folderId)
148                    throws PortalException {
149    
150                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
151                            WebKeys.THEME_DISPLAY);
152    
153                    if (folderId == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
154                            return themeDisplay.translate("home");
155                    }
156    
157                    Folder folder = DLAppLocalServiceUtil.getFolder(folderId);
158    
159                    List<Folder> folders = folder.getAncestors();
160    
161                    Collections.reverse(folders);
162    
163                    StringBundler sb = new StringBundler((folders.size() * 3) + 5);
164    
165                    sb.append(themeDisplay.translate("home"));
166                    sb.append(StringPool.SPACE);
167    
168                    for (Folder curFolder : folders) {
169                            sb.append(StringPool.RAQUO_CHAR);
170                            sb.append(StringPool.SPACE);
171                            sb.append(curFolder.getName());
172                    }
173    
174                    sb.append(StringPool.RAQUO_CHAR);
175                    sb.append(StringPool.SPACE);
176                    sb.append(folder.getName());
177    
178                    return sb.toString();
179            }
180    
181            @Override
182            public Set<String> getAllMediaGalleryMimeTypes() {
183                    return _allMediaGalleryMimeTypes;
184            }
185    
186            @Override
187            public String getDDMStructureKey(DLFileEntryType dlFileEntryType) {
188                    return getDDMStructureKey(dlFileEntryType.getUuid());
189            }
190    
191            @Override
192            public String getDDMStructureKey(String fileEntryTypeUuid) {
193                    return _STRUCTURE_KEY_PREFIX +
194                            StringUtil.toUpperCase(fileEntryTypeUuid);
195            }
196    
197            @Override
198            public String getDeprecatedDDMStructureKey(
199                    DLFileEntryType dlFileEntryType) {
200    
201                    return getDeprecatedDDMStructureKey(
202                            dlFileEntryType.getFileEntryTypeId());
203            }
204    
205            @Override
206            public String getDeprecatedDDMStructureKey(long fileEntryTypeId) {
207                    return _STRUCTURE_KEY_PREFIX + fileEntryTypeId;
208            }
209    
210            @Override
211            public String getDividedPath(long id) {
212                    StringBundler sb = new StringBundler(16);
213    
214                    long dividend = id;
215    
216                    while ((dividend / _DIVISOR) != 0) {
217                            sb.append(StringPool.SLASH);
218                            sb.append(dividend % _DIVISOR);
219    
220                            dividend = dividend / _DIVISOR;
221                    }
222    
223                    sb.append(StringPool.SLASH);
224                    sb.append(id);
225    
226                    return sb.toString();
227            }
228    
229            @Override
230            public String getDLFileEntryControlPanelLink(
231                    PortletRequest portletRequest, long fileEntryId) {
232    
233                    String portletId = PortletProviderUtil.getPortletId(
234                            FileEntry.class.getName(), PortletProvider.Action.MANAGE);
235    
236                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
237                            portletRequest, portletId, PortletRequest.RENDER_PHASE);
238    
239                    portletURL.setParameter(
240                            "mvcRenderCommandName", "/document_library/view_file_entry");
241                    portletURL.setParameter("fileEntryId", String.valueOf(fileEntryId));
242    
243                    return portletURL.toString();
244            }
245    
246            @Override
247            public String getDLFolderControlPanelLink(
248                    PortletRequest portletRequest, long folderId) {
249    
250                    String portletId = PortletProviderUtil.getPortletId(
251                            Folder.class.getName(), PortletProvider.Action.MANAGE);
252    
253                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
254                            portletRequest, portletId, PortletRequest.RENDER_PHASE);
255    
256                    if (folderId == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
257                            portletURL.setParameter(
258                                    "mvcRenderCommandName", "/document_library/view");
259                    }
260                    else {
261                            portletURL.setParameter(
262                                    "mvcRenderCommandName", "/document_library/view_folder");
263                    }
264    
265                    portletURL.setParameter("folderId", String.valueOf(folderId));
266    
267                    return portletURL.toString();
268            }
269    
270            @Override
271            public String getDownloadURL(
272                    FileEntry fileEntry, FileVersion fileVersion, ThemeDisplay themeDisplay,
273                    String queryString) {
274    
275                    return getDownloadURL(
276                            fileEntry, fileVersion, themeDisplay, queryString, true, true);
277            }
278    
279            @Override
280            public String getDownloadURL(
281                    FileEntry fileEntry, FileVersion fileVersion, ThemeDisplay themeDisplay,
282                    String queryString, boolean appendVersion, boolean absoluteURL) {
283    
284                    String previewURL = getPreviewURL(
285                            fileEntry, fileVersion, themeDisplay, queryString, appendVersion,
286                            absoluteURL);
287    
288                    return HttpUtil.addParameter(previewURL, "download", true);
289            }
290    
291            @Override
292            public Map<String, String> getEmailDefinitionTerms(
293                    PortletRequest portletRequest, String emailFromAddress,
294                    String emailFromName) {
295    
296                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
297                            WebKeys.THEME_DISPLAY);
298    
299                    Map<String, String> definitionTerms = new LinkedHashMap<>();
300    
301                    definitionTerms.put(
302                            "[$COMPANY_ID$]",
303                            LanguageUtil.get(
304                                    themeDisplay.getLocale(),
305                                    "the-company-id-associated-with-the-document"));
306                    definitionTerms.put(
307                            "[$COMPANY_MX$]",
308                            LanguageUtil.get(
309                                    themeDisplay.getLocale(),
310                                    "the-company-mx-associated-with-the-document"));
311                    definitionTerms.put(
312                            "[$COMPANY_NAME$]",
313                            LanguageUtil.get(
314                                    themeDisplay.getLocale(),
315                                    "the-company-name-associated-with-the-document"));
316                    definitionTerms.put(
317                            "[$DOCUMENT_TITLE$]",
318                            LanguageUtil.get(themeDisplay.getLocale(), "the-document-title"));
319                    definitionTerms.put(
320                            "[$DOCUMENT_TYPE$]",
321                            LanguageUtil.get(themeDisplay.getLocale(), "the-document-type"));
322                    definitionTerms.put(
323                            "[$DOCUMENT_URL$]",
324                            LanguageUtil.get(themeDisplay.getLocale(), "the-document-url"));
325                    definitionTerms.put(
326                            "[$DOCUMENT_USER_ADDRESS$]",
327                            LanguageUtil.get(
328                                    themeDisplay.getLocale(),
329                                    "the-email-address-of-the-user-who-added-the-document"));
330                    definitionTerms.put(
331                            "[$DOCUMENT_USER_NAME$]",
332                            LanguageUtil.get(
333                                    themeDisplay.getLocale(), "the-user-who-added-the-document"));
334                    definitionTerms.put(
335                            "[$FOLDER_NAME$]",
336                            LanguageUtil.get(
337                                    themeDisplay.getLocale(),
338                                    "the-folder-in-which-the-document-has-been-added"));
339                    definitionTerms.put(
340                            "[$FROM_ADDRESS$]", HtmlUtil.escape(emailFromAddress));
341                    definitionTerms.put("[$FROM_NAME$]", HtmlUtil.escape(emailFromName));
342    
343                    Company company = themeDisplay.getCompany();
344    
345                    definitionTerms.put("[$PORTAL_URL$]", company.getVirtualHostname());
346    
347                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
348    
349                    definitionTerms.put(
350                            "[$PORTLET_NAME$]", HtmlUtil.escape(portletDisplay.getTitle()));
351    
352                    definitionTerms.put(
353                            "[$SITE_NAME$]",
354                            LanguageUtil.get(
355                                    themeDisplay.getLocale(),
356                                    "the-site-name-associated-with-the-document"));
357                    definitionTerms.put(
358                            "[$TO_ADDRESS$]",
359                            LanguageUtil.get(
360                                    themeDisplay.getLocale(),
361                                    "the-address-of-the-email-recipient"));
362                    definitionTerms.put(
363                            "[$TO_NAME$]",
364                            LanguageUtil.get(
365                                    themeDisplay.getLocale(), "the-name-of-the-email-recipient"));
366    
367                    return definitionTerms;
368            }
369    
370            @Override
371            public Map<String, String> getEmailFromDefinitionTerms(
372                    PortletRequest portletRequest, String emailFromAddress,
373                    String emailFromName) {
374    
375                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
376                            WebKeys.THEME_DISPLAY);
377    
378                    Map<String, String> definitionTerms = new LinkedHashMap<>();
379    
380                    definitionTerms.put(
381                            "[$COMPANY_ID$]",
382                            LanguageUtil.get(
383                                    themeDisplay.getLocale(),
384                                    "the-company-id-associated-with-the-document"));
385                    definitionTerms.put(
386                            "[$COMPANY_MX$]",
387                            LanguageUtil.get(
388                                    themeDisplay.getLocale(),
389                                    "the-company-mx-associated-with-the-document"));
390                    definitionTerms.put(
391                            "[$COMPANY_NAME$]",
392                            LanguageUtil.get(
393                                    themeDisplay.getLocale(),
394                                    "the-company-name-associated-with-the-document"));
395                    definitionTerms.put(
396                            "[$DOCUMENT_STATUS_BY_USER_NAME$]",
397                            LanguageUtil.get(
398                                    themeDisplay.getLocale(), "the-user-who-updated-the-document"));
399                    definitionTerms.put(
400                            "[$DOCUMENT_USER_ADDRESS$]",
401                            LanguageUtil.get(
402                                    themeDisplay.getLocale(),
403                                    "the-email-address-of-the-user-who-added-the-document"));
404                    definitionTerms.put(
405                            "[$DOCUMENT_USER_NAME$]",
406                            LanguageUtil.get(
407                                    themeDisplay.getLocale(), "the-user-who-added-the-document"));
408    
409                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
410    
411                    definitionTerms.put(
412                            "[$PORTLET_NAME$]", HtmlUtil.escape(portletDisplay.getTitle()));
413    
414                    definitionTerms.put(
415                            "[$SITE_NAME$]",
416                            LanguageUtil.get(
417                                    themeDisplay.getLocale(),
418                                    "the-site-name-associated-with-the-document"));
419    
420                    return definitionTerms;
421            }
422    
423            @Override
424            public List<FileEntry> getFileEntries(Hits hits) {
425                    List<FileEntry> entries = new ArrayList<>();
426    
427                    for (Document document : hits.getDocs()) {
428                            long fileEntryId = GetterUtil.getLong(
429                                    document.get(Field.ENTRY_CLASS_PK));
430    
431                            try {
432                                    FileEntry fileEntry = DLAppLocalServiceUtil.getFileEntry(
433                                            fileEntryId);
434    
435                                    entries.add(fileEntry);
436                            }
437                            catch (Exception e) {
438                                    if (_log.isWarnEnabled()) {
439                                            _log.warn(
440                                                    "Documents and Media search index is stale and " +
441                                                            "contains file entry " + fileEntryId);
442                                    }
443                            }
444                    }
445    
446                    return entries;
447            }
448    
449            @Override
450            public String getFileEntryImage(
451                    FileEntry fileEntry, ThemeDisplay themeDisplay) {
452    
453                    StringBundler sb = new StringBundler(5);
454    
455                    sb.append("<img src=\"");
456                    sb.append(themeDisplay.getPathThemeImages());
457                    sb.append("/file_system/small/");
458                    sb.append(fileEntry.getIcon());
459                    sb.append(".png\" style=\"border-width: 0; text-align: left;\">");
460    
461                    return sb.toString();
462            }
463    
464            @Override
465            public Set<Long> getFileEntryTypeSubscriptionClassPKs(long userId) {
466                    List<Subscription> subscriptions =
467                            SubscriptionLocalServiceUtil.getUserSubscriptions(
468                                    userId, DLFileEntryType.class.getName());
469    
470                    Set<Long> classPKs = new HashSet<>(subscriptions.size());
471    
472                    for (Subscription subscription : subscriptions) {
473                            classPKs.add(subscription.getClassPK());
474                    }
475    
476                    return classPKs;
477            }
478    
479            @Override
480            public String getFileIcon(String extension) {
481                    if (!_fileIcons.contains(extension)) {
482                            extension = _DEFAULT_FILE_ICON;
483                    }
484    
485                    return extension;
486            }
487    
488            @Override
489            public String getFileIconCssClass(String extension) {
490                    return "documents-and-media";
491            }
492    
493            @Override
494            public String getGenericName(String extension) {
495                    String genericName = _genericNames.get(extension);
496    
497                    if (genericName == null) {
498                            genericName = _DEFAULT_GENERIC_NAME;
499                    }
500    
501                    return genericName;
502            }
503    
504            @Override
505            public String getImagePreviewURL(
506                            FileEntry fileEntry, FileVersion fileVersion,
507                            ThemeDisplay themeDisplay)
508                    throws Exception {
509    
510                    String previewQueryString = null;
511    
512                    if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
513                            if (ImageProcessorUtil.hasImages(fileVersion)) {
514                                    previewQueryString = "&imagePreview=1";
515                            }
516                            else if (PDFProcessorUtil.hasImages(fileVersion)) {
517                                    previewQueryString = "&previewFileIndex=1";
518                            }
519                            else if (VideoProcessorUtil.hasVideo(fileVersion)) {
520                                    previewQueryString = "&videoThumbnail=1";
521                            }
522                    }
523    
524                    return getImageSrc(
525                            fileEntry, fileVersion, themeDisplay, previewQueryString);
526            }
527    
528            @Override
529            public String getImagePreviewURL(
530                            FileEntry fileEntry, ThemeDisplay themeDisplay)
531                    throws Exception {
532    
533                    return getImagePreviewURL(
534                            fileEntry, fileEntry.getFileVersion(), themeDisplay);
535            }
536    
537            @Override
538            public String getPreviewURL(
539                    FileEntry fileEntry, FileVersion fileVersion, ThemeDisplay themeDisplay,
540                    String queryString) {
541    
542                    return getPreviewURL(
543                            fileEntry, fileVersion, themeDisplay, queryString, true, true);
544            }
545    
546            @Override
547            public String getPreviewURL(
548                    FileEntry fileEntry, FileVersion fileVersion, ThemeDisplay themeDisplay,
549                    String queryString, boolean appendVersion, boolean absoluteURL) {
550    
551                    StringBundler sb = new StringBundler(15);
552    
553                    if ((themeDisplay != null) && absoluteURL) {
554                            sb.append(themeDisplay.getPortalURL());
555                    }
556    
557                    sb.append(PortalUtil.getPathContext());
558                    sb.append("/documents/");
559                    sb.append(fileEntry.getRepositoryId());
560                    sb.append(StringPool.SLASH);
561                    sb.append(fileEntry.getFolderId());
562                    sb.append(StringPool.SLASH);
563    
564                    String fileName = fileEntry.getFileName();
565    
566                    if (fileEntry.isInTrash()) {
567                            fileName = TrashUtil.getOriginalTitle(fileEntry.getFileName());
568                    }
569    
570                    sb.append(HttpUtil.encodeURL(HtmlUtil.unescape(fileName)));
571    
572                    sb.append(StringPool.SLASH);
573                    sb.append(HttpUtil.encodeURL(fileEntry.getUuid()));
574    
575                    if (appendVersion) {
576                            sb.append("?version=");
577                            sb.append(fileVersion.getVersion());
578                    }
579    
580                    if (ImageProcessorUtil.isImageSupported(fileVersion)) {
581                            if (appendVersion) {
582                                    sb.append("&t=");
583                            }
584                            else {
585                                    sb.append("?t=");
586                            }
587    
588                            Date modifiedDate = fileVersion.getModifiedDate();
589    
590                            sb.append(modifiedDate.getTime());
591                    }
592    
593                    sb.append(queryString);
594    
595                    String previewURL = sb.toString();
596    
597                    if ((themeDisplay != null) && themeDisplay.isAddSessionIdToURL()) {
598                            return PortalUtil.getURLWithSessionId(
599                                    previewURL, themeDisplay.getSessionId());
600                    }
601    
602                    return previewURL;
603            }
604    
605            @Override
606            public <T> OrderByComparator<T> getRepositoryModelOrderByComparator(
607                    String orderByCol, String orderByType) {
608    
609                    return getRepositoryModelOrderByComparator(
610                            orderByCol, orderByType, false);
611            }
612    
613            @Override
614            public <T> OrderByComparator<T> getRepositoryModelOrderByComparator(
615                    String orderByCol, String orderByType, boolean orderByModel) {
616    
617                    boolean orderByAsc = true;
618    
619                    if (orderByType.equals("desc")) {
620                            orderByAsc = false;
621                    }
622    
623                    OrderByComparator<T> orderByComparator = null;
624    
625                    if (orderByCol.equals("creationDate")) {
626                            orderByComparator = new RepositoryModelCreateDateComparator<>(
627                                    orderByAsc, orderByModel);
628                    }
629                    else if (orderByCol.equals("downloads")) {
630                            orderByComparator = new RepositoryModelReadCountComparator<>(
631                                    orderByAsc, orderByModel);
632                    }
633                    else if (orderByCol.equals("modifiedDate")) {
634                            orderByComparator = new RepositoryModelModifiedDateComparator<>(
635                                    orderByAsc, orderByModel);
636                    }
637                    else if (orderByCol.equals("size")) {
638                            orderByComparator = new RepositoryModelSizeComparator<>(
639                                    orderByAsc, orderByModel);
640                    }
641                    else {
642                            orderByComparator = new RepositoryModelTitleComparator<>(
643                                    orderByAsc, orderByModel);
644                    }
645    
646                    return orderByComparator;
647            }
648    
649            @Override
650            public String getSanitizedFileName(String title, String extension) {
651                    String fileName = StringUtil.replace(
652                            title, CharPool.SLASH, CharPool.UNDERLINE);
653    
654                    if (Validator.isNotNull(extension) &&
655                            !StringUtil.endsWith(fileName, StringPool.PERIOD + extension)) {
656    
657                            fileName += StringPool.PERIOD + extension;
658                    }
659    
660                    if (fileName.length() > 255) {
661                            int x = fileName.length() - 1;
662    
663                            if (Validator.isNotNull(extension)) {
664                                    x = fileName.lastIndexOf(StringPool.PERIOD);
665                            }
666    
667                            int y = x - (fileName.length() - 255);
668    
669                            fileName = fileName.substring(0, y) + fileName.substring(x);
670                    }
671    
672                    return fileName;
673            }
674    
675            @Override
676            public String getTempFileId(long id, String version) {
677                    return getTempFileId(id, version, null);
678            }
679    
680            @Override
681            public String getTempFileId(long id, String version, String languageId) {
682                    if (Validator.isNull(languageId)) {
683                            return String.valueOf(id).concat(StringPool.PERIOD).concat(version);
684                    }
685    
686                    StringBundler sb = new StringBundler(5);
687    
688                    sb.append(id);
689                    sb.append(StringPool.PERIOD);
690                    sb.append(version);
691                    sb.append(StringPool.PERIOD);
692                    sb.append(languageId);
693    
694                    return sb.toString();
695            }
696    
697            /**
698             * @deprecated As of 7.0.0, replaced by {@link #getThumbnailSrc(FileEntry,
699             *             ThemeDisplay)}
700             */
701            @Deprecated
702            @Override
703            public String getThumbnailSrc(
704                            FileEntry fileEntry, DLFileShortcut dlFileShortcut,
705                            ThemeDisplay themeDisplay)
706                    throws Exception {
707    
708                    return getThumbnailSrc(
709                            fileEntry, fileEntry.getFileVersion(), themeDisplay);
710            }
711    
712            /**
713             * @deprecated As of 7.0.0, replaced by {@link #getThumbnailSrc(FileEntry,
714             *             FileVersion, ThemeDisplay)}
715             */
716            @Deprecated
717            @Override
718            public String getThumbnailSrc(
719                            FileEntry fileEntry, FileVersion fileVersion,
720                            DLFileShortcut dlFileShortcut, ThemeDisplay themeDisplay)
721                    throws Exception {
722    
723                    return getThumbnailSrc(fileEntry, fileVersion, themeDisplay);
724            }
725    
726            @Override
727            public String getThumbnailSrc(
728                            FileEntry fileEntry, FileVersion fileVersion,
729                            ThemeDisplay themeDisplay)
730                    throws Exception {
731    
732                    String thumbnailQueryString = null;
733    
734                    if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
735                            if (ImageProcessorUtil.hasImages(fileVersion)) {
736                                    thumbnailQueryString = "&imageThumbnail=1";
737                            }
738                            else if (PDFProcessorUtil.hasImages(fileVersion)) {
739                                    thumbnailQueryString = "&documentThumbnail=1";
740                            }
741                            else if (VideoProcessorUtil.hasVideo(fileVersion)) {
742                                    thumbnailQueryString = "&videoThumbnail=1";
743                            }
744                    }
745    
746                    return getImageSrc(
747                            fileEntry, fileVersion, themeDisplay, thumbnailQueryString);
748            }
749    
750            @Override
751            public String getThumbnailSrc(
752                            FileEntry fileEntry, ThemeDisplay themeDisplay)
753                    throws Exception {
754    
755                    return getThumbnailSrc(
756                            fileEntry, fileEntry.getFileVersion(), themeDisplay);
757            }
758    
759            @Override
760            public String getThumbnailStyle() {
761                    return getThumbnailStyle(true, 0);
762            }
763    
764            @Override
765            public String getThumbnailStyle(boolean max, int margin) {
766                    return getThumbnailStyle(
767                            max, margin,
768                            PrefsPropsUtil.getInteger(
769                                    PropsKeys.DL_FILE_ENTRY_THUMBNAIL_MAX_HEIGHT),
770                            PrefsPropsUtil.getInteger(
771                                    PropsKeys.DL_FILE_ENTRY_THUMBNAIL_MAX_WIDTH));
772            }
773    
774            @Override
775            public String getThumbnailStyle(
776                    boolean max, int margin, int height, int width) {
777    
778                    StringBundler sb = new StringBundler(5);
779    
780                    if (max) {
781                            sb.append("max-height: ");
782                    }
783                    else {
784                            sb.append("height: ");
785                    }
786    
787                    height = height + (2 * margin);
788    
789                    sb.append(height);
790    
791                    if (max) {
792                            sb.append("px; max-width: ");
793                    }
794                    else {
795                            sb.append("px; width: ");
796                    }
797    
798                    width = width + (2 * margin);
799    
800                    sb.append(width);
801    
802                    sb.append("px;");
803    
804                    return sb.toString();
805            }
806    
807            @Override
808            public String getTitleWithExtension(FileEntry fileEntry) {
809                    String title = fileEntry.getTitle();
810                    String extension = fileEntry.getExtension();
811    
812                    return getTitleWithExtension(title, extension);
813            }
814    
815            @Override
816            public String getTitleWithExtension(String title, String extension) {
817                    if (Validator.isNotNull(extension)) {
818                            String periodAndExtension = StringPool.PERIOD.concat(extension);
819    
820                            if (!title.endsWith(periodAndExtension)) {
821                                    title += periodAndExtension;
822                            }
823                    }
824    
825                    return title;
826            }
827    
828            @Override
829            public String getUniqueFileName(
830                    long groupId, long folderId, String fileName) {
831    
832                    String uniqueFileName = fileName;
833    
834                    for (int i = 1;; i++) {
835                            try {
836                                    DLAppLocalServiceUtil.getFileEntry(
837                                            groupId, folderId, uniqueFileName);
838    
839                                    uniqueFileName = FileUtil.appendParentheticalSuffix(
840                                            fileName, String.valueOf(i));
841                            }
842                            catch (Exception e) {
843                                    break;
844                            }
845                    }
846    
847                    return uniqueFileName;
848            }
849    
850            @Override
851            public String getWebDavURL(
852                            ThemeDisplay themeDisplay, Folder folder, FileEntry fileEntry)
853                    throws PortalException {
854    
855                    return getWebDavURL(themeDisplay, folder, fileEntry, false);
856            }
857    
858            @Override
859            public String getWebDavURL(
860                            ThemeDisplay themeDisplay, Folder folder, FileEntry fileEntry,
861                            boolean manualCheckInRequired)
862                    throws PortalException {
863    
864                    return getWebDavURL(
865                            themeDisplay, folder, fileEntry, manualCheckInRequired, false);
866            }
867    
868            @Override
869            public String getWebDavURL(
870                            ThemeDisplay themeDisplay, Folder folder, FileEntry fileEntry,
871                            boolean manualCheckInRequired, boolean openDocumentUrl)
872                    throws PortalException {
873    
874                    StringBundler webDavURL = new StringBundler(7);
875    
876                    boolean secure = false;
877    
878                    if (themeDisplay.isSecure() ||
879                            PropsValues.WEBDAV_SERVLET_HTTPS_REQUIRED) {
880    
881                            secure = true;
882                    }
883    
884                    String portalURL = PortalUtil.getPortalURL(
885                            themeDisplay.getServerName(), themeDisplay.getServerPort(), secure);
886    
887                    webDavURL.append(portalURL);
888    
889                    webDavURL.append(themeDisplay.getPathContext());
890                    webDavURL.append("/webdav");
891    
892                    if (manualCheckInRequired) {
893                            webDavURL.append(MANUAL_CHECK_IN_REQUIRED_PATH);
894                    }
895    
896                    Group group = null;
897    
898                    if (fileEntry != null) {
899                            group = GroupLocalServiceUtil.getGroup(fileEntry.getGroupId());
900                    }
901                    else {
902                            group = themeDisplay.getScopeGroup();
903                    }
904    
905                    webDavURL.append(group.getFriendlyURL());
906                    webDavURL.append("/document_library");
907    
908                    StringBuilder sb = new StringBuilder();
909    
910                    if ((folder != null) &&
911                            (folder.getFolderId() !=
912                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID)) {
913    
914                            Folder curFolder = folder;
915    
916                            while (true) {
917                                    sb.insert(0, HttpUtil.encodeURL(curFolder.getName(), true));
918                                    sb.insert(0, StringPool.SLASH);
919    
920                                    if (curFolder.getParentFolderId() ==
921                                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
922    
923                                            break;
924                                    }
925    
926                                    curFolder = DLAppLocalServiceUtil.getFolder(
927                                            curFolder.getParentFolderId());
928                            }
929                    }
930    
931                    if (fileEntry != null) {
932                            sb.append(StringPool.SLASH);
933                            sb.append(DLWebDAVUtil.escapeURLTitle(fileEntry.getTitle()));
934                    }
935    
936                    webDavURL.append(sb.toString());
937    
938                    return webDavURL.toString();
939            }
940    
941            @Override
942            public boolean hasWorkflowDefinitionLink(
943                            long companyId, long groupId, long folderId, long fileEntryTypeId)
944                    throws Exception {
945    
946                    while (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
947                            DLFolder dlFolder = DLFolderLocalServiceUtil.fetchDLFolder(
948                                    folderId);
949    
950                            if (dlFolder == null) {
951                                    return false;
952                            }
953    
954                            if (dlFolder.getRestrictionType() !=
955                                            DLFolderConstants.RESTRICTION_TYPE_INHERIT) {
956    
957                                    break;
958                            }
959    
960                            folderId = dlFolder.getParentFolderId();
961                    }
962    
963                    if (WorkflowDefinitionLinkLocalServiceUtil.hasWorkflowDefinitionLink(
964                                    companyId, groupId, DLFolderConstants.getClassName(), folderId,
965                                    fileEntryTypeId) ||
966                            WorkflowDefinitionLinkLocalServiceUtil.hasWorkflowDefinitionLink(
967                                    companyId, groupId, DLFolderConstants.getClassName(), folderId,
968                                    DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_ALL)) {
969    
970                            return true;
971                    }
972    
973                    return false;
974            }
975    
976            @Override
977            public boolean isAutoGeneratedDLFileEntryTypeDDMStructureKey(
978                    String ddmStructureKey) {
979    
980                    if (ddmStructureKey.startsWith(_STRUCTURE_KEY_PREFIX)) {
981                            return true;
982                    }
983    
984                    return false;
985            }
986    
987            @Override
988            public boolean isOfficeExtension(String extension) {
989                    return ArrayUtil.contains(_MICROSOFT_OFFICE_EXTENSIONS, extension);
990            }
991    
992            @Override
993            public boolean isSubscribedToFileEntryType(
994                    long companyId, long groupId, long userId, long fileEntryTypeId) {
995    
996                    if (fileEntryTypeId ==
997                                    DLFileEntryTypeConstants.FILE_ENTRY_TYPE_ID_BASIC_DOCUMENT) {
998    
999                            fileEntryTypeId = groupId;
1000                    }
1001    
1002                    return SubscriptionLocalServiceUtil.isSubscribed(
1003                            companyId, userId, DLFileEntryType.class.getName(),
1004                            fileEntryTypeId);
1005            }
1006    
1007            @Override
1008            public boolean isSubscribedToFolder(
1009                            long companyId, long groupId, long userId, long folderId)
1010                    throws PortalException {
1011    
1012                    return isSubscribedToFolder(companyId, groupId, userId, folderId, true);
1013            }
1014    
1015            @Override
1016            public boolean isSubscribedToFolder(
1017                            long companyId, long groupId, long userId, long folderId,
1018                            boolean recursive)
1019                    throws PortalException {
1020    
1021                    List<Long> ancestorFolderIds = new ArrayList<>();
1022    
1023                    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
1024                            Folder folder = DLAppLocalServiceUtil.getFolder(folderId);
1025    
1026                            ancestorFolderIds.add(folderId);
1027    
1028                            if (recursive) {
1029                                    ancestorFolderIds.addAll(folder.getAncestorFolderIds());
1030    
1031                                    ancestorFolderIds.add(groupId);
1032                            }
1033                    }
1034                    else {
1035                            ancestorFolderIds.add(groupId);
1036                    }
1037    
1038                    long[] folderIdsArray = ArrayUtil.toLongArray(ancestorFolderIds);
1039    
1040                    return SubscriptionLocalServiceUtil.isSubscribed(
1041                            companyId, userId, DLFolder.class.getName(), folderIdsArray);
1042            }
1043    
1044            @Override
1045            public boolean isValidVersion(String version) {
1046                    if (version.equals(DLFileEntryConstants.PRIVATE_WORKING_COPY_VERSION)) {
1047                            return true;
1048                    }
1049    
1050                    String[] versionParts = StringUtil.split(version, StringPool.PERIOD);
1051    
1052                    if (versionParts.length != 2) {
1053                            return false;
1054                    }
1055    
1056                    if (Validator.isNumber(versionParts[0]) &&
1057                            Validator.isNumber(versionParts[1])) {
1058    
1059                            return true;
1060                    }
1061    
1062                    return false;
1063            }
1064    
1065            @Override
1066            public void startWorkflowInstance(
1067                            long userId, DLFileVersion dlFileVersion, String syncEventType,
1068                            ServiceContext serviceContext)
1069                    throws PortalException {
1070    
1071                    Map<String, Serializable> workflowContext = new HashMap<>();
1072    
1073                    workflowContext.put(
1074                            WorkflowConstants.CONTEXT_URL,
1075                            getEntryURL(dlFileVersion, serviceContext));
1076                    workflowContext.put("event", syncEventType);
1077    
1078                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
1079                            dlFileVersion.getCompanyId(), dlFileVersion.getGroupId(), userId,
1080                            DLFileEntryConstants.getClassName(),
1081                            dlFileVersion.getFileVersionId(), dlFileVersion, serviceContext,
1082                            workflowContext);
1083            }
1084    
1085            protected String getEntryURL(
1086                            DLFileVersion dlFileVersion, ServiceContext serviceContext)
1087                    throws PortalException {
1088    
1089                    if (Objects.equals(
1090                                    serviceContext.getCommand(), Constants.ADD_WEBDAV) ||
1091                            Objects.equals(
1092                                    serviceContext.getCommand(), Constants.UPDATE_WEBDAV)) {
1093    
1094                            return serviceContext.getPortalURL() +
1095                                    serviceContext.getCurrentURL();
1096                    }
1097    
1098                    String entryURL = GetterUtil.getString(
1099                            serviceContext.getAttribute("entryURL"));
1100    
1101                    if (Validator.isNotNull(entryURL)) {
1102                            return entryURL;
1103                    }
1104    
1105                    HttpServletRequest request = serviceContext.getRequest();
1106                    ThemeDisplay themeDisplay = serviceContext.getThemeDisplay();
1107    
1108                    if ((request == null) || (themeDisplay == null)) {
1109                            return StringPool.BLANK;
1110                    }
1111    
1112                    PortletURL portletURL = null;
1113    
1114                    long plid = serviceContext.getPlid();
1115                    long controlPanelPlid = PortalUtil.getControlPanelPlid(
1116                            serviceContext.getCompanyId());
1117                    String portletId = PortletProviderUtil.getPortletId(
1118                            FileEntry.class.getName(), PortletProvider.Action.VIEW);
1119    
1120                    for (PortletLayoutFinder portletLayoutFinder : _serviceTrackerList) {
1121                            try {
1122                                    PortletLayoutFinder.Result result = portletLayoutFinder.find(
1123                                            themeDisplay, themeDisplay.getSiteGroupId());
1124    
1125                                    portletId = result.getPortletId();
1126                                    plid = result.getPlid();
1127    
1128                                    break;
1129                            }
1130                            catch (PortalException pe) {
1131                            }
1132                    }
1133    
1134                    if ((plid == controlPanelPlid) ||
1135                            (plid == LayoutConstants.DEFAULT_PLID)) {
1136    
1137                            portletURL = PortalUtil.getControlPanelPortletURL(
1138                                    request, portletId, PortletRequest.RENDER_PHASE);
1139                    }
1140                    else {
1141                            portletURL = PortletURLFactoryUtil.create(
1142                                    request, portletId, plid, PortletRequest.RENDER_PHASE);
1143                    }
1144    
1145                    portletURL.setParameter(
1146                            "mvcRenderCommandName", "/document_library/view_file_entry");
1147                    portletURL.setParameter(
1148                            "fileEntryId", String.valueOf(dlFileVersion.getFileEntryId()));
1149    
1150                    return portletURL.toString();
1151            }
1152    
1153            protected String getImageSrc(
1154                            FileEntry fileEntry, FileVersion fileVersion,
1155                            ThemeDisplay themeDisplay, String queryString)
1156                    throws Exception {
1157    
1158                    String thumbnailSrc = StringPool.BLANK;
1159    
1160                    if (Validator.isNotNull(queryString)) {
1161                            thumbnailSrc = getPreviewURL(
1162                                    fileEntry, fileVersion, themeDisplay, queryString, true, true);
1163                    }
1164    
1165                    return thumbnailSrc;
1166            }
1167    
1168            private static void _populateGenericNamesMap(String genericName) {
1169                    String[] extensions = PropsUtil.getArray(
1170                            PropsKeys.DL_FILE_GENERIC_EXTENSIONS, new Filter(genericName));
1171    
1172                    for (String extension : extensions) {
1173                            _genericNames.put(extension, genericName);
1174                    }
1175            }
1176    
1177            private static final String _DEFAULT_FILE_ICON = "page";
1178    
1179            private static final String _DEFAULT_GENERIC_NAME = "default";
1180    
1181            private static final long _DIVISOR = 256;
1182    
1183            private static final String[] _MICROSOFT_OFFICE_EXTENSIONS = {
1184                    "accda", "accdb", "accdc", "accde", "accdp", "accdr", "accdt", "accdu",
1185                    "acl", "ade", "adp", "asd", "cnv", "crtx", "doc", "docm", "docx", "dot",
1186                    "dotm", "dotx", "grv", "iaf", "laccdb", "maf", "mam", "maq", "mar",
1187                    "mat", "mda", "mdb", "mde", "mdt", "mdw", "mpd", "mpp", "mpt", "oab",
1188                    "obi", "oft", "olm", "one", "onepkg", "ops", "ost", "pa", "pip", "pot",
1189                    "potm", "potx", "ppa", "ppam", "pps", "ppsm", "ppsx", "ppt", "pptm",
1190                    "pptx", "prf", "pst", "pub", "puz", "rpmsg", "sldm", "sldx", "slk",
1191                    "snp", "svd", "thmx", "vdx", "vrge08message", "vsd", "vss", "vst",
1192                    "vsx", "vtx", "wbk", "wll", "xar", "xl", "xla", "xlam", "xlb", "xlc",
1193                    "xll", "xlm", "xls", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx",
1194                    "xlw", "xsf", "xsn"
1195            };
1196    
1197            private static final String _STRUCTURE_KEY_PREFIX = "AUTO_";
1198    
1199            private static final Log _log = LogFactoryUtil.getLog(DLImpl.class);
1200    
1201            private static final Set<String> _allMediaGalleryMimeTypes =
1202                    new TreeSet<>();
1203            private static final Set<String> _fileIcons = new HashSet<>();
1204            private static final Map<String, String> _genericNames = new HashMap<>();
1205    
1206            static {
1207                    _allMediaGalleryMimeTypes.addAll(
1208                            SetUtil.fromArray(
1209                                    PropsUtil.getArray(
1210                                            PropsKeys.DL_FILE_ENTRY_PREVIEW_AUDIO_MIME_TYPES)));
1211                    _allMediaGalleryMimeTypes.addAll(
1212                            SetUtil.fromArray(
1213                                    PropsUtil.getArray(
1214                                            PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_MIME_TYPES)));
1215                    _allMediaGalleryMimeTypes.addAll(
1216                            SetUtil.fromArray(
1217                                    PropsUtil.getArray(
1218                                            PropsKeys.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES)));
1219    
1220                    String[] fileIcons = null;
1221    
1222                    try {
1223                            fileIcons = PropsUtil.getArray(PropsKeys.DL_FILE_ICONS);
1224                    }
1225                    catch (Exception e) {
1226                            if (_log.isDebugEnabled()) {
1227                                    _log.debug(e, e);
1228                            }
1229    
1230                            fileIcons = new String[] {StringPool.BLANK};
1231                    }
1232    
1233                    for (int i = 0; i < fileIcons.length; i++) {
1234    
1235                            // Only process non wildcard extensions
1236    
1237                            if (!StringPool.STAR.equals(fileIcons[i])) {
1238    
1239                                    // Strip starting period
1240    
1241                                    String extension = fileIcons[i];
1242    
1243                                    if (extension.length() > 0) {
1244                                            extension = extension.substring(1);
1245                                    }
1246    
1247                                    _fileIcons.add(extension);
1248                            }
1249                    }
1250    
1251                    String[] genericNames = PropsUtil.getArray(
1252                            PropsKeys.DL_FILE_GENERIC_NAMES);
1253    
1254                    for (String genericName : genericNames) {
1255                            _populateGenericNamesMap(genericName);
1256                    }
1257            }
1258    
1259            private final ServiceTrackerList<PortletLayoutFinder> _serviceTrackerList =
1260                    ServiceTrackerCollections.openList(
1261                            PortletLayoutFinder.class,
1262                            "(model.class.name=" + FileEntry.class.getName() + ")");
1263    
1264    }