001    /**
002     * Copyright (c) 2000-2013 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.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.util.FileUtil;
020    import com.liferay.portal.kernel.util.ReflectionUtil;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.util.PropsValues;
024    import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
025    import com.liferay.portlet.documentlibrary.DuplicateFileException;
026    import com.liferay.portlet.documentlibrary.NoSuchDirectoryException;
027    import com.liferay.portlet.documentlibrary.NoSuchFileException;
028    import com.liferay.portlet.documentlibrary.util.DLUtil;
029    
030    import java.io.File;
031    import java.io.FileInputStream;
032    import java.io.FileNotFoundException;
033    import java.io.IOException;
034    import java.io.InputStream;
035    
036    import java.util.Arrays;
037    import java.util.Map;
038    import java.util.concurrent.ConcurrentHashMap;
039    
040    /**
041     * @author Brian Wing Shun Chan
042     * @author Sten Martinez
043     * @author Alexander Chow
044     * @author Edward Han
045     */
046    public class FileSystemStore extends BaseStore {
047    
048            public FileSystemStore() {
049                    try {
050                            FileUtil.mkdirs(_rootDir);
051                    }
052                    catch (IOException ioe) {
053                            ReflectionUtil.throwException(ioe);
054                    }
055            }
056    
057            @Override
058            public void addDirectory(long companyId, long repositoryId, String dirName)
059                    throws PortalException {
060    
061                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
062    
063                    if (dirNameDir.exists()) {
064                            throw new DuplicateDirectoryException(dirNameDir.getPath());
065                    }
066    
067                    try {
068                            FileUtil.mkdirs(dirNameDir);
069                    }
070                    catch (IOException ioe) {
071                            ReflectionUtil.throwException(ioe);
072                    }
073            }
074    
075            @Override
076            public void addFile(
077                            long companyId, long repositoryId, String fileName, InputStream is)
078                    throws PortalException, SystemException {
079    
080                    try {
081                            File fileNameVersionFile = getFileNameVersionFile(
082                                    companyId, repositoryId, fileName, VERSION_DEFAULT);
083    
084                            if (fileNameVersionFile.exists()) {
085                                    throw new DuplicateFileException(fileNameVersionFile.getPath());
086                            }
087    
088                            FileUtil.write(fileNameVersionFile, is);
089                    }
090                    catch (IOException ioe) {
091                            throw new SystemException(ioe);
092                    }
093            }
094    
095            @Override
096            public void checkRoot(long companyId) {
097            }
098    
099            @Override
100            public void copyFileVersion(
101                            long companyId, long repositoryId, String fileName,
102                            String fromVersionLabel, String toVersionLabel)
103                    throws PortalException, SystemException {
104    
105                    File fromFileNameVersionFile = getFileNameVersionFile(
106                            companyId, repositoryId, fileName, fromVersionLabel);
107    
108                    File toFileNameVersionFile = getFileNameVersionFile(
109                            companyId, repositoryId, fileName, toVersionLabel);
110    
111                    if (toFileNameVersionFile.exists()) {
112                            throw new DuplicateFileException(toFileNameVersionFile.getPath());
113                    }
114    
115                    try {
116                            toFileNameVersionFile.createNewFile();
117    
118                            FileUtil.copyFile(fromFileNameVersionFile, toFileNameVersionFile);
119                    }
120                    catch (IOException ioe) {
121                            throw new SystemException(ioe);
122                    }
123            }
124    
125            @Override
126            public void deleteDirectory(
127                            long companyId, long repositoryId, String dirName)
128                    throws PortalException {
129    
130                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
131    
132                    if (!dirNameDir.exists()) {
133                            throw new NoSuchDirectoryException(dirNameDir.getPath());
134                    }
135    
136                    File parentFile = dirNameDir.getParentFile();
137    
138                    FileUtil.deltree(dirNameDir);
139    
140                    RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
141                            companyId, repositoryId);
142    
143                    _repositoryDirs.remove(repositoryDirKey);
144    
145                    deleteEmptyAncestors(parentFile);
146            }
147    
148            @Override
149            public void deleteFile(long companyId, long repositoryId, String fileName)
150                    throws PortalException {
151    
152                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
153    
154                    if (!fileNameDir.exists()) {
155                            throw new NoSuchFileException(fileNameDir.getPath());
156                    }
157    
158                    File parentFile = fileNameDir.getParentFile();
159    
160                    FileUtil.deltree(fileNameDir);
161    
162                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
163            }
164    
165            @Override
166            public void deleteFile(
167                            long companyId, long repositoryId, String fileName,
168                            String versionLabel)
169                    throws PortalException {
170    
171                    File fileNameVersionFile = getFileNameVersionFile(
172                            companyId, repositoryId, fileName, versionLabel);
173    
174                    if (!fileNameVersionFile.exists()) {
175                            throw new NoSuchFileException(fileNameVersionFile.getPath());
176                    }
177    
178                    File parentFile = fileNameVersionFile.getParentFile();
179    
180                    fileNameVersionFile.delete();
181    
182                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
183            }
184    
185            @Override
186            public File getFile(
187                            long companyId, long repositoryId, String fileName,
188                            String versionLabel)
189                    throws PortalException {
190    
191                    if (Validator.isNull(versionLabel)) {
192                            versionLabel = getHeadVersionLabel(
193                                    companyId, repositoryId, fileName);
194                    }
195    
196                    File fileNameVersionFile = getFileNameVersionFile(
197                            companyId, repositoryId, fileName, versionLabel);
198    
199                    if (!fileNameVersionFile.exists()) {
200                            throw new NoSuchFileException(fileNameVersionFile.getPath());
201                    }
202    
203                    return fileNameVersionFile;
204            }
205    
206            @Override
207            public InputStream getFileAsStream(
208                            long companyId, long repositoryId, String fileName,
209                            String versionLabel)
210                    throws PortalException {
211    
212                    if (Validator.isNull(versionLabel)) {
213                            versionLabel = getHeadVersionLabel(
214                                    companyId, repositoryId, fileName);
215                    }
216    
217                    File fileNameVersionFile = getFileNameVersionFile(
218                            companyId, repositoryId, fileName, versionLabel);
219    
220                    try {
221                            return new FileInputStream(fileNameVersionFile);
222                    }
223                    catch (FileNotFoundException fnfe) {
224                            throw new NoSuchFileException(fileNameVersionFile.getPath(), fnfe);
225                    }
226            }
227    
228            @Override
229            public String[] getFileNames(long companyId, long repositoryId) {
230                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
231    
232                    return FileUtil.listDirs(repositoryDir);
233            }
234    
235            @Override
236            public String[] getFileNames(
237                            long companyId, long repositoryId, String dirName)
238                    throws PortalException {
239    
240                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
241    
242                    if (!dirNameDir.exists()) {
243                            throw new NoSuchDirectoryException(dirNameDir.getPath());
244                    }
245    
246                    String[] fileNames = FileUtil.listDirs(dirNameDir);
247    
248                    Arrays.sort(fileNames);
249    
250                    // Convert /${fileName} to /${dirName}/${fileName}
251    
252                    for (int i = 0; i < fileNames.length; i++) {
253                            fileNames[i] =
254                                    StringPool.SLASH + dirName + StringPool.SLASH + fileNames[i];
255                    }
256    
257                    return fileNames;
258            }
259    
260            @Override
261            public long getFileSize(long companyId, long repositoryId, String fileName)
262                    throws PortalException {
263    
264                    String versionLabel = getHeadVersionLabel(
265                            companyId, repositoryId, fileName);
266    
267                    File fileNameVersionFile = getFileNameVersionFile(
268                            companyId, repositoryId, fileName, versionLabel);
269    
270                    if (!fileNameVersionFile.exists()) {
271                            throw new NoSuchFileException(fileNameVersionFile.getPath());
272                    }
273    
274                    return fileNameVersionFile.length();
275            }
276    
277            @Override
278            public boolean hasDirectory(
279                    long companyId, long repositoryId, String dirName) {
280    
281                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
282    
283                    return dirNameDir.exists();
284            }
285    
286            @Override
287            public boolean hasFile(
288                    long companyId, long repositoryId, String fileName,
289                    String versionLabel) {
290    
291                    File fileNameVersionFile = getFileNameVersionFile(
292                            companyId, repositoryId, fileName, versionLabel);
293    
294                    if (fileNameVersionFile.exists()) {
295                            return true;
296                    }
297                    else {
298                            return false;
299                    }
300            }
301    
302            @Override
303            public void move(String srcDir, String destDir) {
304            }
305    
306            @Override
307            public void updateFile(
308                            long companyId, long repositoryId, long newRepositoryId,
309                            String fileName)
310                    throws PortalException, SystemException {
311    
312                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
313                    File newFileNameDir = getFileNameDir(
314                            companyId, newRepositoryId, fileName);
315    
316                    if (newFileNameDir.exists()) {
317                            throw new DuplicateFileException(fileName);
318                    }
319    
320                    File parentFile = fileNameDir.getParentFile();
321    
322                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
323    
324                    if (!renamed) {
325                            throw new SystemException(
326                                    "File name directory was not renamed from " +
327                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
328                    }
329    
330                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
331            }
332    
333            @Override
334            public void updateFile(
335                            long companyId, long repositoryId, String fileName,
336                            String newFileName)
337                    throws PortalException, SystemException {
338    
339                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
340                    File newFileNameDir = getFileNameDir(
341                            companyId, repositoryId, newFileName);
342    
343                    if (newFileNameDir.exists()) {
344                            throw new DuplicateFileException(newFileName);
345                    }
346    
347                    File parentFile = fileNameDir.getParentFile();
348    
349                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
350    
351                    if (!renamed) {
352                            throw new SystemException(
353                                    "File name directory was not renamed from " +
354                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
355                    }
356    
357                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
358            }
359    
360            @Override
361            public void updateFile(
362                            long companyId, long repositoryId, String fileName,
363                            String versionLabel, InputStream is)
364                    throws PortalException, SystemException {
365    
366                    try {
367                            File fileNameVersionFile = getFileNameVersionFile(
368                                    companyId, repositoryId, fileName, versionLabel);
369    
370                            if (fileNameVersionFile.exists()) {
371                                    throw new DuplicateFileException(fileNameVersionFile.getPath());
372                            }
373    
374                            FileUtil.write(fileNameVersionFile, is);
375                    }
376                    catch (IOException ioe) {
377                            throw new SystemException(ioe);
378                    }
379            }
380    
381            @Override
382            public void updateFileVersion(
383                            long companyId, long repositoryId, String fileName,
384                            String fromVersionLabel, String toVersionLabel)
385                    throws PortalException, SystemException {
386    
387                    File fromFileNameVersionFile = getFileNameVersionFile(
388                            companyId, repositoryId, fileName, fromVersionLabel);
389    
390                    File toFileNameVersionFile = getFileNameVersionFile(
391                            companyId, repositoryId, fileName, toVersionLabel);
392    
393                    if (toFileNameVersionFile.exists()) {
394                            throw new DuplicateFileException(toFileNameVersionFile.getPath());
395                    }
396    
397                    boolean renamed = FileUtil.move(
398                            fromFileNameVersionFile, toFileNameVersionFile);
399    
400                    if (!renamed) {
401                            throw new SystemException(
402                                    "File name version file was not renamed from " +
403                                            fromFileNameVersionFile.getPath() + " to " +
404                                                    toFileNameVersionFile.getPath());
405                    }
406            }
407    
408            protected void deleteEmptyAncestors(File file) {
409                    deleteEmptyAncestors(-1, -1, file);
410            }
411    
412            protected void deleteEmptyAncestors(
413                    long companyId, long repositoryId, File file) {
414    
415                    String[] fileNames = file.list();
416    
417                    if ((fileNames == null) || (fileNames.length > 0)) {
418                            return;
419                    }
420    
421                    String fileName = file.getName();
422    
423                    if ((repositoryId > 0) &&
424                            fileName.equals(String.valueOf(repositoryId))) {
425    
426                            RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
427                                    companyId, repositoryId);
428    
429                            _repositoryDirs.remove(repositoryDirKey);
430                    }
431    
432                    File parentFile = file.getParentFile();
433    
434                    if (file.delete() && (parentFile != null)) {
435                            deleteEmptyAncestors(companyId, repositoryId, parentFile);
436                    }
437            }
438    
439            protected File getCompanyDir(long companyId) {
440                    File companyDir = new File(_rootDir + StringPool.SLASH + companyId);
441    
442                    try {
443                            FileUtil.mkdirs(companyDir);
444                    }
445                    catch (IOException ioe) {
446                            ReflectionUtil.throwException(ioe);
447                    }
448    
449                    return companyDir;
450            }
451    
452            protected File getDirNameDir(
453                    long companyId, long repositoryId, String dirName) {
454    
455                    return getFileNameDir(companyId, repositoryId, dirName);
456            }
457    
458            protected File getFileNameDir(
459                    long companyId, long repositoryId, String fileName) {
460    
461                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
462    
463                    File fileNameDir = new File(
464                            repositoryDir + StringPool.SLASH + fileName);
465    
466                    return fileNameDir;
467            }
468    
469            protected File getFileNameVersionFile(
470                    long companyId, long repositoryId, String fileName, String version) {
471    
472                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
473    
474                    File fileNameVersionFile = new File(
475                            fileNameDir + StringPool.SLASH + version);
476    
477                    return fileNameVersionFile;
478            }
479    
480            protected String getHeadVersionLabel(
481                    long companyId, long repositoryId, String fileName) {
482    
483                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
484    
485                    if (!fileNameDir.exists()) {
486                            return VERSION_DEFAULT;
487                    }
488    
489                    String[] versionLabels = FileUtil.listFiles(fileNameDir);
490    
491                    String headVersionLabel = VERSION_DEFAULT;
492    
493                    for (String versionLabel : versionLabels) {
494                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
495                                    headVersionLabel = versionLabel;
496                            }
497                    }
498    
499                    return headVersionLabel;
500            }
501    
502            protected File getRepositoryDir(long companyId, long repositoryId) {
503                    RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
504                            companyId, repositoryId);
505    
506                    File repositoryDir = _repositoryDirs.get(repositoryDirKey);
507    
508                    if (repositoryDir == null) {
509                            File companyDir = getCompanyDir(companyId);
510    
511                            repositoryDir = new File(
512                                    companyDir + StringPool.SLASH + repositoryId);
513    
514                            try {
515                                    FileUtil.mkdirs(repositoryDir);
516                            }
517                            catch (IOException ioe) {
518                                    ReflectionUtil.throwException(ioe);
519                            }
520    
521                            _repositoryDirs.put(repositoryDirKey, repositoryDir);
522                    }
523    
524                    return repositoryDir;
525            }
526    
527            private Map<RepositoryDirKey, File> _repositoryDirs =
528                    new ConcurrentHashMap<RepositoryDirKey, File>();
529            private File _rootDir = new File(PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR);
530    
531            private class RepositoryDirKey {
532    
533                    public RepositoryDirKey(long companyId, long repositoryId) {
534                            _companyId = companyId;
535                            _repositoryId = repositoryId;
536                    }
537    
538                    @Override
539                    public boolean equals(Object obj) {
540                            RepositoryDirKey repositoryDirKey = (RepositoryDirKey)obj;
541    
542                            if ((_companyId == repositoryDirKey._companyId) &&
543                                    (_repositoryId == repositoryDirKey._repositoryId)) {
544    
545                                    return true;
546                            }
547                            else {
548                                    return false;
549                            }
550                    }
551    
552                    @Override
553                    public int hashCode() {
554                            return (int)(_companyId * 11 + _repositoryId);
555                    }
556    
557                    private long _companyId;
558                    private long _repositoryId;
559    
560            }
561    
562    }