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