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.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            @Override
220            public String[] getFileNames(long companyId, long repositoryId) {
221                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
222    
223                    return FileUtil.listDirs(repositoryDir);
224            }
225    
226            @Override
227            public String[] getFileNames(
228                            long companyId, long repositoryId, String dirName)
229                    throws PortalException {
230    
231                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
232    
233                    if (!dirNameDir.exists()) {
234                            throw new NoSuchDirectoryException(dirNameDir.getPath());
235                    }
236    
237                    String[] fileNames = FileUtil.listDirs(dirNameDir);
238    
239                    Arrays.sort(fileNames);
240    
241                    // Convert /${fileName} to /${dirName}/${fileName}
242    
243                    for (int i = 0; i < fileNames.length; i++) {
244                            fileNames[i] =
245                                    StringPool.SLASH + dirName + StringPool.SLASH + fileNames[i];
246                    }
247    
248                    return fileNames;
249            }
250    
251            @Override
252            public long getFileSize(long companyId, long repositoryId, String fileName)
253                    throws PortalException {
254    
255                    String versionLabel = getHeadVersionLabel(
256                            companyId, repositoryId, fileName);
257    
258                    File fileNameVersionFile = getFileNameVersionFile(
259                            companyId, repositoryId, fileName, versionLabel);
260    
261                    if (!fileNameVersionFile.exists()) {
262                            throw new NoSuchFileException(fileNameVersionFile.getPath());
263                    }
264    
265                    return fileNameVersionFile.length();
266            }
267    
268            @Override
269            public boolean hasDirectory(
270                    long companyId, long repositoryId, String dirName) {
271    
272                    File dirNameDir = getDirNameDir(companyId, repositoryId, dirName);
273    
274                    return dirNameDir.exists();
275            }
276    
277            @Override
278            public boolean hasFile(
279                    long companyId, long repositoryId, String fileName,
280                    String versionLabel) {
281    
282                    File fileNameVersionFile = getFileNameVersionFile(
283                            companyId, repositoryId, fileName, versionLabel);
284    
285                    if (fileNameVersionFile.exists()) {
286                            return true;
287                    }
288                    else {
289                            return false;
290                    }
291            }
292    
293            @Override
294            public void move(String srcDir, String destDir) {
295            }
296    
297            @Override
298            public void updateFile(
299                            long companyId, long repositoryId, long newRepositoryId,
300                            String fileName)
301                    throws PortalException, SystemException {
302    
303                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
304                    File newFileNameDir = getFileNameDir(
305                            companyId, newRepositoryId, fileName);
306    
307                    if (newFileNameDir.exists()) {
308                            throw new DuplicateFileException(fileName);
309                    }
310    
311                    File parentFile = fileNameDir.getParentFile();
312    
313                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
314    
315                    if (!renamed) {
316                            throw new SystemException(
317                                    "File name directory was not renamed from " +
318                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
319                    }
320    
321                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
322            }
323    
324            @Override
325            public void updateFile(
326                            long companyId, long repositoryId, String fileName,
327                            String newFileName)
328                    throws PortalException, SystemException {
329    
330                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
331                    File newFileNameDir = getFileNameDir(
332                            companyId, repositoryId, newFileName);
333    
334                    if (newFileNameDir.exists()) {
335                            throw new DuplicateFileException(newFileName);
336                    }
337    
338                    File parentFile = fileNameDir.getParentFile();
339    
340                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
341    
342                    if (!renamed) {
343                            throw new SystemException(
344                                    "File name directory was not renamed from " +
345                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
346                    }
347    
348                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
349            }
350    
351            @Override
352            public void updateFile(
353                            long companyId, long repositoryId, String fileName,
354                            String versionLabel, InputStream is)
355                    throws PortalException, SystemException {
356    
357                    try {
358                            File fileNameVersionFile = getFileNameVersionFile(
359                                    companyId, repositoryId, fileName, versionLabel);
360    
361                            if (fileNameVersionFile.exists()) {
362                                    throw new DuplicateFileException(fileNameVersionFile.getPath());
363                            }
364    
365                            FileUtil.write(fileNameVersionFile, is);
366                    }
367                    catch (IOException ioe) {
368                            throw new SystemException(ioe);
369                    }
370            }
371    
372            @Override
373            public void updateFileVersion(
374                            long companyId, long repositoryId, String fileName,
375                            String fromVersionLabel, String toVersionLabel)
376                    throws PortalException, SystemException {
377    
378                    File fromFileNameVersionFile = getFileNameVersionFile(
379                            companyId, repositoryId, fileName, fromVersionLabel);
380    
381                    File toFileNameVersionFile = getFileNameVersionFile(
382                            companyId, repositoryId, fileName, toVersionLabel);
383    
384                    if (toFileNameVersionFile.exists()) {
385                            throw new DuplicateFileException(toFileNameVersionFile.getPath());
386                    }
387    
388                    boolean renamed = FileUtil.move(
389                            fromFileNameVersionFile, toFileNameVersionFile);
390    
391                    if (!renamed) {
392                            throw new SystemException(
393                                    "File name version file was not renamed from " +
394                                            fromFileNameVersionFile.getPath() + " to " +
395                                                    toFileNameVersionFile.getPath());
396                    }
397            }
398    
399            protected void deleteEmptyAncestors(File file) {
400                    deleteEmptyAncestors(-1, -1, file);
401            }
402    
403            protected void deleteEmptyAncestors(
404                    long companyId, long repositoryId, File file) {
405    
406                    String[] fileNames = file.list();
407    
408                    if ((fileNames == null) || (fileNames.length > 0)) {
409                            return;
410                    }
411    
412                    String fileName = file.getName();
413    
414                    if ((repositoryId > 0) &&
415                            fileName.equals(String.valueOf(repositoryId))) {
416    
417                            RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
418                                    companyId, repositoryId);
419    
420                            _repositoryDirs.remove(repositoryDirKey);
421                    }
422    
423                    File parentFile = file.getParentFile();
424    
425                    if (file.delete() && (parentFile != null)) {
426                            deleteEmptyAncestors(companyId, repositoryId, parentFile);
427                    }
428            }
429    
430            protected File getCompanyDir(long companyId) {
431                    File companyDir = new File(_rootDir + StringPool.SLASH + companyId);
432    
433                    if (!companyDir.exists()) {
434                            companyDir.mkdirs();
435                    }
436    
437                    return companyDir;
438            }
439    
440            protected File getDirNameDir(
441                    long companyId, long repositoryId, String dirName) {
442    
443                    return getFileNameDir(companyId, repositoryId, dirName);
444            }
445    
446            protected File getFileNameDir(
447                    long companyId, long repositoryId, String fileName) {
448    
449                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
450    
451                    File fileNameDir = new File(
452                            repositoryDir + StringPool.SLASH + fileName);
453    
454                    return fileNameDir;
455            }
456    
457            protected File getFileNameVersionFile(
458                    long companyId, long repositoryId, String fileName, String version) {
459    
460                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
461    
462                    File fileNameVersionFile = new File(
463                            fileNameDir + StringPool.SLASH + version);
464    
465                    return fileNameVersionFile;
466            }
467    
468            protected String getHeadVersionLabel(
469                    long companyId, long repositoryId, String fileName) {
470    
471                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
472    
473                    if (!fileNameDir.exists()) {
474                            return VERSION_DEFAULT;
475                    }
476    
477                    String[] versionLabels = FileUtil.listFiles(fileNameDir);
478    
479                    String headVersionLabel = VERSION_DEFAULT;
480    
481                    for (String versionLabel : versionLabels) {
482                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
483                                    headVersionLabel = versionLabel;
484                            }
485                    }
486    
487                    return headVersionLabel;
488            }
489    
490            protected File getRepositoryDir(long companyId, long repositoryId) {
491                    RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
492                            companyId, repositoryId);
493    
494                    File repositoryDir = _repositoryDirs.get(repositoryDirKey);
495    
496                    if (repositoryDir == null) {
497                            File companyDir = getCompanyDir(companyId);
498    
499                            repositoryDir = new File(
500                                    companyDir + StringPool.SLASH + repositoryId);
501    
502                            if (!repositoryDir.exists()) {
503                                    repositoryDir.mkdirs();
504                            }
505    
506                            _repositoryDirs.put(repositoryDirKey, repositoryDir);
507                    }
508    
509                    return repositoryDir;
510            }
511    
512            private Map<RepositoryDirKey, File> _repositoryDirs =
513                    new ConcurrentHashMap<RepositoryDirKey, File>();
514            private File _rootDir = new File(PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR);
515    
516            private class RepositoryDirKey {
517    
518                    public RepositoryDirKey(long companyId, long repositoryId) {
519                            _companyId = companyId;
520                            _repositoryId = repositoryId;
521                    }
522    
523                    @Override
524                    public boolean equals(Object obj) {
525                            RepositoryDirKey repositoryDirKey = (RepositoryDirKey)obj;
526    
527                            if ((_companyId == repositoryDirKey._companyId) &&
528                                    (_repositoryId == repositoryDirKey._repositoryId)) {
529    
530                                    return true;
531                            }
532                            else {
533                                    return false;
534                            }
535                    }
536    
537                    @Override
538                    public int hashCode() {
539                            return (int)(_companyId * 11 + _repositoryId);
540                    }
541    
542                    private long _companyId;
543                    private long _repositoryId;
544    
545            }
546    
547    }