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