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