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