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