001    /**
002     * Copyright (c) 2000-2012 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.store;
016    
017    import com.liferay.portal.kernel.bean.BeanReference;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.io.ByteArrayFileInputStream;
021    import com.liferay.portal.kernel.search.BooleanClauseOccur;
022    import com.liferay.portal.kernel.search.BooleanQuery;
023    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
024    import com.liferay.portal.kernel.search.Field;
025    import com.liferay.portal.kernel.search.Hits;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.SearchContext;
029    import com.liferay.portal.kernel.search.SearchEngineUtil;
030    import com.liferay.portal.kernel.search.TermQuery;
031    import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
032    import com.liferay.portal.kernel.util.FileUtil;
033    import com.liferay.portal.kernel.util.PropsKeys;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.TempFileUtil;
037    import com.liferay.portal.kernel.util.Validator;
038    import com.liferay.portal.model.Group;
039    import com.liferay.portal.security.permission.ActionKeys;
040    import com.liferay.portal.security.permission.PermissionChecker;
041    import com.liferay.portal.security.permission.PermissionThreadLocal;
042    import com.liferay.portal.service.GroupLocalService;
043    import com.liferay.portal.util.PrefsPropsUtil;
044    import com.liferay.portal.util.PropsValues;
045    import com.liferay.portlet.documentlibrary.DirectoryNameException;
046    import com.liferay.portlet.documentlibrary.FileExtensionException;
047    import com.liferay.portlet.documentlibrary.FileNameException;
048    import com.liferay.portlet.documentlibrary.FileSizeException;
049    import com.liferay.portlet.documentlibrary.SourceFileNameException;
050    import com.liferay.portlet.documentlibrary.antivirus.AntivirusScannerUtil;
051    import com.liferay.portlet.documentlibrary.model.DLFileEntryConstants;
052    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
053    import com.liferay.portlet.documentlibrary.service.permission.DLFolderPermission;
054    
055    import java.io.File;
056    import java.io.IOException;
057    import java.io.InputStream;
058    
059    /**
060     * @author Brian Wing Shun Chan
061     * @author Alexander Chow
062     * @author Edward Han
063     */
064    public class DLStoreImpl implements DLStore {
065    
066            public void addDirectory(long companyId, long repositoryId, String dirName)
067                    throws PortalException, SystemException {
068    
069                    if (!isValidName(dirName) || dirName.equals("/")) {
070                            throw new DirectoryNameException(dirName);
071                    }
072    
073                    store.addDirectory(companyId, repositoryId, dirName);
074            }
075    
076            public void addFile(
077                            long companyId, long repositoryId, String fileName,
078                            boolean validateFileExtension, byte[] bytes)
079                    throws PortalException, SystemException {
080    
081                    validate(fileName, validateFileExtension, bytes);
082    
083                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
084                            AntivirusScannerUtil.scan(bytes);
085                    }
086    
087                    store.addFile(companyId, repositoryId, fileName, bytes);
088            }
089    
090            public void addFile(
091                            long companyId, long repositoryId, String fileName,
092                            boolean validateFileExtension, File file)
093                    throws PortalException, SystemException {
094    
095                    validate(fileName, validateFileExtension, file);
096    
097                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
098                            AntivirusScannerUtil.scan(file);
099                    }
100    
101                    store.addFile(companyId, repositoryId, fileName, file);
102            }
103    
104            public void addFile(
105                            long companyId, long repositoryId, String fileName,
106                            boolean validateFileExtension, InputStream is)
107                    throws PortalException, SystemException {
108    
109                    if (is instanceof ByteArrayFileInputStream) {
110                            ByteArrayFileInputStream byteArrayFileInputStream =
111                                    (ByteArrayFileInputStream)is;
112    
113                            File file = byteArrayFileInputStream.getFile();
114    
115                            addFile(
116                                    companyId, repositoryId, fileName, validateFileExtension, file);
117    
118                            return;
119                    }
120    
121                    validate(fileName, validateFileExtension, is);
122    
123                    if (!PropsValues.DL_STORE_ANTIVIRUS_ENABLED ||
124                            !AntivirusScannerUtil.isActive()) {
125    
126                            store.addFile(companyId, repositoryId, fileName, is);
127                    }
128                    else {
129                            File tempFile = null;
130    
131                            try {
132                                    if (is.markSupported()) {
133                                            is.mark(is.available() + 1);
134    
135                                            AntivirusScannerUtil.scan(is);
136    
137                                            is.reset();
138    
139                                            store.addFile(companyId, repositoryId, fileName, is);
140                                    }
141                                    else {
142                                            tempFile = FileUtil.createTempFile();
143    
144                                            FileUtil.write(tempFile, is);
145    
146                                            AntivirusScannerUtil.scan(tempFile);
147    
148                                            store.addFile(companyId, repositoryId, fileName, tempFile);
149                                    }
150                            }
151                            catch (IOException ioe) {
152                                    throw new SystemException(
153                                            "Unable to scan file " + fileName, ioe);
154                            }
155                            finally {
156                                    if (tempFile != null) {
157                                            tempFile.delete();
158                                    }
159                            }
160                    }
161            }
162    
163            public void addFile(
164                            long companyId, long repositoryId, String fileName, byte[] bytes)
165                    throws PortalException, SystemException {
166    
167                    addFile(companyId, repositoryId, fileName, true, bytes);
168            }
169    
170            public void addFile(
171                            long companyId, long repositoryId, String fileName, File file)
172                    throws PortalException, SystemException {
173    
174                    addFile(companyId, repositoryId, fileName, true, file);
175            }
176    
177            public void addFile(
178                            long companyId, long repositoryId, String fileName, InputStream is)
179                    throws PortalException, SystemException {
180    
181                    addFile(companyId, repositoryId, fileName, true, is);
182            }
183    
184            public void checkRoot(long companyId) throws SystemException {
185                    store.checkRoot(companyId);
186            }
187    
188            public void copyFileVersion(
189                            long companyId, long repositoryId, String fileName,
190                            String fromVersionLabel, String toVersionLabel)
191                    throws PortalException, SystemException {
192    
193                    store.copyFileVersion(
194                            companyId, repositoryId, fileName, fromVersionLabel,
195                            toVersionLabel);
196            }
197    
198            public void deleteDirectory(
199                            long companyId, long repositoryId, String dirName)
200                    throws PortalException, SystemException {
201    
202                    store.deleteDirectory(companyId, repositoryId, dirName);
203            }
204    
205            public void deleteFile(long companyId, long repositoryId, String fileName)
206                    throws PortalException, SystemException {
207    
208                    validate(fileName, false);
209    
210                    store.deleteFile(companyId, repositoryId, fileName);
211            }
212    
213            public void deleteFile(
214                            long companyId, long repositoryId, String fileName,
215                            String versionLabel)
216                    throws PortalException, SystemException {
217    
218                    validate(fileName, false);
219    
220                    store.deleteFile(companyId, repositoryId, fileName, versionLabel);
221            }
222    
223            public File getFile(long companyId, long repositoryId, String fileName)
224                    throws PortalException, SystemException {
225    
226                    validate(fileName, false);
227    
228                    return store.getFile(companyId, repositoryId, fileName);
229            }
230    
231            public File getFile(
232                            long companyId, long repositoryId, String fileName,
233                            String versionLabel)
234                    throws PortalException, SystemException {
235    
236                    validate(fileName, false);
237    
238                    return store.getFile(companyId, repositoryId, fileName, versionLabel);
239            }
240    
241            public byte[] getFileAsBytes(
242                            long companyId, long repositoryId, String fileName)
243                    throws PortalException, SystemException {
244    
245                    validate(fileName, false);
246    
247                    return store.getFileAsBytes(companyId, repositoryId, fileName);
248            }
249    
250            public byte[] getFileAsBytes(
251                            long companyId, long repositoryId, String fileName,
252                            String versionLabel)
253                    throws PortalException, SystemException {
254    
255                    validate(fileName, false);
256    
257                    return store.getFileAsBytes(
258                            companyId, repositoryId, fileName, versionLabel);
259            }
260    
261            public InputStream getFileAsStream(
262                            long companyId, long repositoryId, String fileName)
263                    throws PortalException, SystemException {
264    
265                    validate(fileName, false);
266    
267                    return store.getFileAsStream(companyId, repositoryId, fileName);
268            }
269    
270            public InputStream getFileAsStream(
271                            long companyId, long repositoryId, String fileName,
272                            String versionLabel)
273                    throws PortalException, SystemException {
274    
275                    validate(fileName, false);
276    
277                    return store.getFileAsStream(
278                            companyId, repositoryId, fileName, versionLabel);
279            }
280    
281            public String[] getFileNames(
282                            long companyId, long repositoryId, String dirName)
283                    throws PortalException, SystemException {
284    
285                    if (!isValidName(dirName)) {
286                            throw new DirectoryNameException(dirName);
287                    }
288    
289                    return store.getFileNames(companyId, repositoryId, dirName);
290            }
291    
292            public long getFileSize(long companyId, long repositoryId, String fileName)
293                    throws PortalException, SystemException {
294    
295                    validate(fileName, false);
296    
297                    return store.getFileSize(companyId, repositoryId, fileName);
298            }
299    
300            public boolean hasDirectory(
301                            long companyId, long repositoryId, String dirName)
302                    throws PortalException, SystemException {
303    
304                    if (!isValidName(dirName)) {
305                            throw new DirectoryNameException(dirName);
306                    }
307    
308                    return store.hasDirectory(companyId, repositoryId, dirName);
309            }
310    
311            public boolean hasFile(long companyId, long repositoryId, String fileName)
312                    throws PortalException, SystemException {
313    
314                    validate(fileName, false);
315    
316                    return store.hasFile(companyId, repositoryId, fileName);
317            }
318    
319            public boolean hasFile(
320                            long companyId, long repositoryId, String fileName,
321                            String versionLabel)
322                    throws PortalException, SystemException {
323    
324                    validate(fileName, false);
325    
326                    return store.hasFile(companyId, repositoryId, fileName, versionLabel);
327            }
328    
329            public void move(String srcDir, String destDir) throws SystemException {
330                    store.move(srcDir, destDir);
331            }
332    
333            public Hits search(
334                            long companyId, long userId, String portletId, long groupId,
335                            long[] repositoryIds, String keywords, int start, int end)
336                    throws SystemException {
337    
338                    try {
339                            SearchContext searchContext = new SearchContext();
340    
341                            searchContext.setCompanyId(companyId);
342                            searchContext.setEnd(end);
343                            searchContext.setEntryClassNames(
344                                    new String[] {DLFileEntryConstants.getClassName()});
345                            searchContext.setGroupIds(new long[] {groupId});
346    
347                            Indexer indexer = IndexerRegistryUtil.getIndexer(
348                                    DLFileEntryConstants.getClassName());
349    
350                            searchContext.setSearchEngineId(indexer.getSearchEngineId());
351    
352                            searchContext.setStart(start);
353                            searchContext.setUserId(userId);
354    
355                            BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
356                                    searchContext);
357    
358                            contextQuery.addRequiredTerm(Field.PORTLET_ID, portletId);
359    
360                            if (groupId > 0) {
361                                    Group group = groupLocalService.getGroup(groupId);
362    
363                                    if (group.isLayout()) {
364                                            contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
365    
366                                            groupId = group.getParentGroupId();
367                                    }
368    
369                                    contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
370                            }
371    
372                            if ((repositoryIds != null) && (repositoryIds.length > 0)) {
373                                    BooleanQuery repositoryIdsQuery =
374                                            BooleanQueryFactoryUtil.create(searchContext);
375    
376                                    for (long repositoryId : repositoryIds) {
377                                            try {
378                                                    if (userId > 0) {
379                                                            PermissionChecker permissionChecker =
380                                                                    PermissionThreadLocal.getPermissionChecker();
381    
382                                                            DLFolderPermission.check(
383                                                                    permissionChecker, groupId, repositoryId,
384                                                                    ActionKeys.VIEW);
385                                                    }
386    
387                                                    if (repositoryId ==
388                                                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
389    
390                                                            repositoryId = groupId;
391                                                    }
392    
393                                                    TermQuery termQuery = TermQueryFactoryUtil.create(
394                                                            searchContext, "repositoryId", repositoryId);
395    
396                                                    repositoryIdsQuery.add(
397                                                            termQuery, BooleanClauseOccur.SHOULD);
398                                            }
399                                            catch (Exception e) {
400                                            }
401                                    }
402    
403                                    contextQuery.add(repositoryIdsQuery, BooleanClauseOccur.MUST);
404                            }
405    
406                            BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
407                                    searchContext);
408    
409                            searchQuery.addTerms(_KEYWORDS_FIELDS, keywords);
410    
411                            BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(
412                                    searchContext);
413    
414                            fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
415    
416                            if (searchQuery.clauses().size() > 0) {
417                                    fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
418                            }
419    
420                            return SearchEngineUtil.search(searchContext, fullQuery);
421                    }
422                    catch (Exception e) {
423                            throw new SystemException(e);
424                    }
425            }
426    
427            public void updateFile(
428                            long companyId, long repositoryId, long newRepositoryId,
429                            String fileName)
430                    throws PortalException, SystemException {
431    
432                    store.updateFile(companyId, repositoryId, newRepositoryId, fileName);
433            }
434    
435            public void updateFile(
436                            long companyId, long repositoryId, String fileName,
437                            String newFileName)
438                    throws PortalException, SystemException {
439    
440                    store.updateFile(companyId, repositoryId, fileName, newFileName);
441            }
442    
443            public void updateFile(
444                            long companyId, long repositoryId, String fileName,
445                            String fileExtension, boolean validateFileExtension,
446                            String versionLabel, String sourceFileName, File file)
447                    throws PortalException, SystemException {
448    
449                    validate(
450                            fileName, fileExtension, sourceFileName, validateFileExtension,
451                            file);
452    
453                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
454                            AntivirusScannerUtil.scan(file);
455                    }
456    
457                    store.updateFile(companyId, repositoryId, fileName, versionLabel, file);
458            }
459    
460            public void updateFile(
461                            long companyId, long repositoryId, String fileName,
462                            String fileExtension, boolean validateFileExtension,
463                            String versionLabel, String sourceFileName, InputStream is)
464                    throws PortalException, SystemException {
465    
466                    if (is instanceof ByteArrayFileInputStream) {
467                            ByteArrayFileInputStream byteArrayFileInputStream =
468                                    (ByteArrayFileInputStream)is;
469    
470                            File file = byteArrayFileInputStream.getFile();
471    
472                            updateFile(
473                                    companyId, repositoryId, fileName, fileExtension,
474                                    validateFileExtension, versionLabel, sourceFileName, file);
475    
476                            return;
477                    }
478    
479                    validate(
480                            fileName, fileExtension, sourceFileName, validateFileExtension, is);
481    
482                    if (!PropsValues.DL_STORE_ANTIVIRUS_ENABLED ||
483                            !AntivirusScannerUtil.isActive()) {
484    
485                            store.updateFile(
486                                    companyId, repositoryId, fileName, versionLabel, is);
487                    }
488                    else {
489                            File tempFile = null;
490    
491                            try {
492                                    if (is.markSupported()) {
493                                            is.mark(is.available() + 1);
494    
495                                            AntivirusScannerUtil.scan(is);
496    
497                                            is.reset();
498    
499                                            store.updateFile(
500                                                    companyId, repositoryId, fileName, versionLabel, is);
501                                    }
502                                    else {
503                                            tempFile = FileUtil.createTempFile();
504    
505                                            FileUtil.write(tempFile, is);
506    
507                                            AntivirusScannerUtil.scan(tempFile);
508    
509                                            store.updateFile(
510                                                    companyId, repositoryId, fileName, versionLabel,
511                                                    tempFile);
512                                    }
513                            }
514                            catch (IOException ioe) {
515                                    throw new SystemException(
516                                            "Unable to scan file " + fileName, ioe);
517                            }
518                            finally {
519                                    if (tempFile != null) {
520                                            tempFile.delete();
521                                    }
522                            }
523                    }
524            }
525    
526            public void updateFileVersion(
527                            long companyId, long repositoryId, String fileName,
528                            String fromVersionLabel, String toVersionLabel)
529                    throws PortalException, SystemException {
530    
531                    store.updateFileVersion(
532                            companyId, repositoryId, fileName, fromVersionLabel,
533                            toVersionLabel);
534            }
535    
536            public void validate(String fileName, boolean validateFileExtension)
537                    throws PortalException, SystemException {
538    
539                    if (!isValidName(fileName)) {
540                            throw new FileNameException(fileName);
541                    }
542    
543                    if (fileName.endsWith(TempFileUtil.SUFFIX_TEMP_FILE_NAME)) {
544                            fileName = StringUtil.replaceLast(
545                                    fileName, TempFileUtil.SUFFIX_TEMP_FILE_NAME, StringPool.BLANK);
546                    }
547    
548                    if (validateFileExtension) {
549                            boolean validFileExtension = false;
550    
551                            String[] fileExtensions = PrefsPropsUtil.getStringArray(
552                                    PropsKeys.DL_FILE_EXTENSIONS, StringPool.COMMA);
553    
554                            for (String fileExtension : fileExtensions) {
555                                    if (StringPool.STAR.equals(fileExtension) ||
556                                            StringUtil.endsWith(fileName, fileExtension)) {
557    
558                                            validFileExtension = true;
559    
560                                            break;
561                                    }
562                            }
563    
564                            if (!validFileExtension) {
565                                    throw new FileExtensionException(fileName);
566                            }
567                    }
568            }
569    
570            public void validate(
571                            String fileName, boolean validateFileExtension, byte[] bytes)
572                    throws PortalException, SystemException {
573    
574                    validate(fileName, validateFileExtension);
575    
576                    if ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
577                            ((bytes == null) ||
578                             (bytes.length >
579                                     PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
580    
581                            throw new FileSizeException(fileName);
582                    }
583            }
584    
585            public void validate(
586                            String fileName, boolean validateFileExtension, File file)
587                    throws PortalException, SystemException {
588    
589                    validate(fileName, validateFileExtension);
590    
591                    if ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
592                            ((file == null) ||
593                             (file.length() >
594                                    PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
595    
596                            throw new FileSizeException(fileName);
597                    }
598            }
599    
600            public void validate(
601                            String fileName, boolean validateFileExtension, InputStream is)
602                    throws PortalException, SystemException {
603    
604                    validate(fileName, validateFileExtension);
605    
606                    // LEP-4851
607    
608                    try {
609                            if ((is == null) ||
610                                    ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
611                                     (is.available() >
612                                            PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
613    
614                                    throw new FileSizeException(fileName);
615                            }
616                    }
617                    catch (IOException ioe) {
618                            throw new FileSizeException(ioe.getMessage());
619                    }
620            }
621    
622            public void validate(
623                            String fileName, String fileExtension, String sourceFileName,
624                            boolean validateFileExtension, File file)
625                    throws PortalException, SystemException {
626    
627                    validate(
628                            fileName, fileExtension, sourceFileName, validateFileExtension);
629    
630                    if ((file != null) &&
631                            (PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
632                            (file.length() >
633                                    PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE))) {
634    
635                            throw new FileSizeException(fileName);
636                    }
637            }
638    
639            public void validate(
640                            String fileName, String fileExtension, String sourceFileName,
641                            boolean validateFileExtension, InputStream is)
642                    throws PortalException, SystemException {
643    
644                    validate(
645                            fileName, fileExtension, sourceFileName, validateFileExtension);
646    
647                    try {
648                            if ((is != null) &&
649                                    (PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
650                                    (is.available() >
651                                            PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE))) {
652    
653                                    throw new FileSizeException(fileName);
654                            }
655                    }
656                    catch (IOException ioe) {
657                            throw new FileSizeException(ioe.getMessage());
658                    }
659            }
660    
661            protected boolean isValidName(String name) {
662                    if ((name == null) ||
663                            name.contains("\\") ||
664                            name.contains("\\\\") ||
665                            name.contains("//") ||
666                            name.contains(":") ||
667                            name.contains("*") ||
668                            name.contains("?") ||
669                            name.contains("\"") ||
670                            name.contains("<") ||
671                            name.contains(">") ||
672                            name.contains("|") ||
673                            name.contains("[") ||
674                            name.contains("]") ||
675                            name.contains("../") ||
676                            name.contains("/..")) {
677    
678                            return false;
679                    }
680    
681                    return true;
682            }
683    
684            protected void validate(
685                            String fileName, String fileExtension, String sourceFileName,
686                            boolean validateFileExtension)
687                    throws PortalException, SystemException {
688    
689                    String sourceFileExtension = FileUtil.getExtension(sourceFileName);
690    
691                    if (Validator.isNotNull(sourceFileName) &&
692                            PropsValues.DL_FILE_EXTENSIONS_STRICT_CHECK &&
693                            !fileExtension.equals(sourceFileExtension)) {
694    
695                            throw new SourceFileNameException(sourceFileExtension);
696                    }
697    
698                    validate(fileName, validateFileExtension);
699            }
700    
701            @BeanReference(type = GroupLocalService.class)
702            protected GroupLocalService groupLocalService;
703    
704            @BeanReference(type = Store.class)
705            protected Store store;
706    
707            private static final String[] _KEYWORDS_FIELDS = {
708                    Field.ASSET_TAG_NAMES, Field.CONTENT, Field.PROPERTIES
709            };
710    
711    }