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