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            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, SystemException {
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                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
313    
314                    if (!renamed) {
315                            throw new SystemException(
316                                    "File name directory was not renamed from " +
317                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
318                    }
319    
320                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
321            }
322    
323            public void updateFile(
324                            long companyId, long repositoryId, String fileName,
325                            String newFileName)
326                    throws PortalException, SystemException {
327    
328                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
329                    File newFileNameDir = getFileNameDir(
330                            companyId, repositoryId, newFileName);
331    
332                    if (newFileNameDir.exists()) {
333                            throw new DuplicateFileException(newFileName);
334                    }
335    
336                    File parentFile = fileNameDir.getParentFile();
337    
338                    boolean renamed = FileUtil.move(fileNameDir, newFileNameDir);
339    
340                    if (!renamed) {
341                            throw new SystemException(
342                                    "File name directory was not renamed from " +
343                                            fileNameDir.getPath() + " to " + newFileNameDir.getPath());
344                    }
345    
346                    deleteEmptyAncestors(companyId, repositoryId, parentFile);
347            }
348    
349            @Override
350            public void updateFile(
351                            long companyId, long repositoryId, String fileName,
352                            String versionLabel, InputStream is)
353                    throws PortalException, SystemException {
354    
355                    try {
356                            File fileNameVersionFile = getFileNameVersionFile(
357                                    companyId, repositoryId, fileName, versionLabel);
358    
359                            if (fileNameVersionFile.exists()) {
360                                    throw new DuplicateFileException(fileNameVersionFile.getPath());
361                            }
362    
363                            FileUtil.write(fileNameVersionFile, is);
364                    }
365                    catch (IOException ioe) {
366                            throw new SystemException(ioe);
367                    }
368            }
369    
370            @Override
371            public void updateFileVersion(
372                            long companyId, long repositoryId, String fileName,
373                            String fromVersionLabel, String toVersionLabel)
374                    throws PortalException, SystemException {
375    
376                    File fromFileNameVersionFile = getFileNameVersionFile(
377                            companyId, repositoryId, fileName, fromVersionLabel);
378    
379                    File toFileNameVersionFile = getFileNameVersionFile(
380                            companyId, repositoryId, fileName, toVersionLabel);
381    
382                    if (toFileNameVersionFile.exists()) {
383                            throw new DuplicateFileException(toFileNameVersionFile.getPath());
384                    }
385    
386                    boolean renamed = FileUtil.move(
387                            fromFileNameVersionFile, toFileNameVersionFile);
388    
389                    if (!renamed) {
390                            throw new SystemException(
391                                    "File name version file was not renamed from " +
392                                            fromFileNameVersionFile.getPath() + " to " +
393                                                    toFileNameVersionFile.getPath());
394                    }
395            }
396    
397            protected void deleteEmptyAncestors(File file) {
398                    deleteEmptyAncestors(-1, -1, file);
399            }
400    
401            protected void deleteEmptyAncestors(
402                    long companyId, long repositoryId, File file) {
403    
404                    String[] fileNames = file.list();
405    
406                    if ((fileNames == null) || (fileNames.length > 0)) {
407                            return;
408                    }
409    
410                    String fileName = file.getName();
411    
412                    if ((repositoryId > 0) &&
413                            fileName.equals(String.valueOf(repositoryId))) {
414    
415                            RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
416                                    companyId, repositoryId);
417    
418                            _repositoryDirs.remove(repositoryDirKey);
419                    }
420    
421                    File parentFile = file.getParentFile();
422    
423                    if (file.delete() && (parentFile != null)) {
424                            deleteEmptyAncestors(companyId, repositoryId, parentFile);
425                    }
426            }
427    
428            protected File getCompanyDir(long companyId) {
429                    File companyDir = new File(_rootDir + StringPool.SLASH + companyId);
430    
431                    if (!companyDir.exists()) {
432                            companyDir.mkdirs();
433                    }
434    
435                    return companyDir;
436            }
437    
438            protected File getDirNameDir(
439                    long companyId, long repositoryId, String dirName) {
440    
441                    return getFileNameDir(companyId, repositoryId, dirName);
442            }
443    
444            protected File getFileNameDir(
445                    long companyId, long repositoryId, String fileName) {
446    
447                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
448    
449                    File fileNameDir = new File(
450                            repositoryDir + StringPool.SLASH + fileName);
451    
452                    return fileNameDir;
453            }
454    
455            protected File getFileNameVersionFile(
456                    long companyId, long repositoryId, String fileName, String version) {
457    
458                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
459    
460                    File fileNameVersionFile = new File(
461                            fileNameDir + StringPool.SLASH + version);
462    
463                    return fileNameVersionFile;
464            }
465    
466            protected String getHeadVersionLabel(
467                    long companyId, long repositoryId, String fileName) {
468    
469                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
470    
471                    if (!fileNameDir.exists()) {
472                            return VERSION_DEFAULT;
473                    }
474    
475                    String[] versionLabels = FileUtil.listFiles(fileNameDir);
476    
477                    String headVersionLabel = VERSION_DEFAULT;
478    
479                    for (String versionLabel : versionLabels) {
480                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
481                                    headVersionLabel = versionLabel;
482                            }
483                    }
484    
485                    return headVersionLabel;
486            }
487    
488            protected File getRepositoryDir(long companyId, long repositoryId) {
489                    RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
490                            companyId, repositoryId);
491    
492                    File repositoryDir = _repositoryDirs.get(repositoryDirKey);
493    
494                    if (repositoryDir == null) {
495                            File companyDir = getCompanyDir(companyId);
496    
497                            repositoryDir = new File(
498                                    companyDir + StringPool.SLASH + repositoryId);
499    
500                            if (!repositoryDir.exists()) {
501                                    repositoryDir.mkdirs();
502                            }
503    
504                            _repositoryDirs.put(repositoryDirKey, repositoryDir);
505                    }
506    
507                    return repositoryDir;
508            }
509    
510            private Map<RepositoryDirKey, File> _repositoryDirs =
511                    new ConcurrentHashMap<RepositoryDirKey, File>();
512            private File _rootDir = new File(PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR);
513    
514            private class RepositoryDirKey {
515    
516                    public RepositoryDirKey(long companyId, long repositoryId) {
517                            _companyId = companyId;
518                            _repositoryId = repositoryId;
519                    }
520    
521                    @Override
522                    public boolean equals(Object obj) {
523                            RepositoryDirKey repositoryDirKey = (RepositoryDirKey)obj;
524    
525                            if ((_companyId == repositoryDirKey._companyId) &&
526                                    (_repositoryId == repositoryDirKey._repositoryId)) {
527    
528                                    return true;
529                            }
530                            else {
531                                    return false;
532                            }
533                    }
534    
535                    @Override
536                    public int hashCode() {
537                            return (int)(_companyId * 11 + _repositoryId);
538                    }
539    
540                    private long _companyId;
541                    private long _repositoryId;
542    
543            }
544    
545    }