001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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 == null) || (fileNames.length > 0)) {
387                            return;
388                    }
389    
390                    String fileName = file.getName();
391    
392                    if ((repositoryId > 0) &&
393                            fileName.equals(String.valueOf(repositoryId))) {
394    
395                            RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
396                                    companyId, repositoryId);
397    
398                            _repositoryDirs.remove(repositoryDirKey);
399                    }
400    
401                    File parentFile = file.getParentFile();
402    
403                    if (file.delete() && (parentFile != null)) {
404                            deleteEmptyAncestors(companyId, repositoryId, parentFile);
405                    }
406            }
407    
408            protected File getCompanyDir(long companyId) {
409                    File companyDir = new File(_rootDir + StringPool.SLASH + companyId);
410    
411                    if (!companyDir.exists()) {
412                            companyDir.mkdirs();
413                    }
414    
415                    return companyDir;
416            }
417    
418            protected File getDirNameDir(
419                    long companyId, long repositoryId, String dirName) {
420    
421                    return getFileNameDir(companyId, repositoryId, dirName);
422            }
423    
424            protected File getFileNameDir(
425                    long companyId, long repositoryId, String fileName) {
426    
427                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
428    
429                    File fileNameDir = new File(
430                            repositoryDir + StringPool.SLASH + fileName);
431    
432                    return fileNameDir;
433            }
434    
435            protected File getFileNameVersionFile(
436                    long companyId, long repositoryId, String fileName, String version) {
437    
438                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
439    
440                    File fileNameVersionFile = new File(
441                            fileNameDir + StringPool.SLASH + version);
442    
443                    return fileNameVersionFile;
444            }
445    
446            protected String getHeadVersionLabel(
447                    long companyId, long repositoryId, String fileName) {
448    
449                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
450    
451                    if (!fileNameDir.exists()) {
452                            return VERSION_DEFAULT;
453                    }
454    
455                    String[] versionLabels = FileUtil.listFiles(fileNameDir);
456    
457                    String headVersionLabel = VERSION_DEFAULT;
458    
459                    for (String versionLabel : versionLabels) {
460                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
461                                    headVersionLabel = versionLabel;
462                            }
463                    }
464    
465                    return headVersionLabel;
466            }
467    
468            protected File getRepositoryDir(long companyId, long repositoryId) {
469                    RepositoryDirKey repositoryDirKey = new RepositoryDirKey(
470                            companyId, repositoryId);
471    
472                    File repositoryDir = _repositoryDirs.get(repositoryDirKey);
473    
474                    if (repositoryDir == null) {
475                            File companyDir = getCompanyDir(companyId);
476    
477                            repositoryDir = new File(
478                                    companyDir + StringPool.SLASH + repositoryId);
479    
480                            if (!repositoryDir.exists()) {
481                                    repositoryDir.mkdirs();
482                            }
483    
484                            _repositoryDirs.put(repositoryDirKey, repositoryDir);
485                    }
486    
487                    return repositoryDir;
488            }
489    
490            private Map<RepositoryDirKey, File> _repositoryDirs =
491                    new ConcurrentHashMap<RepositoryDirKey, File>();
492            private File _rootDir = new File(PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR);
493    
494            private class RepositoryDirKey {
495    
496                    public RepositoryDirKey(long companyId, long repositoryId) {
497                            _companyId = companyId;
498                            _repositoryId = repositoryId;
499                    }
500    
501                    @Override
502                    public boolean equals(Object obj) {
503                            RepositoryDirKey repositoryDirKey = (RepositoryDirKey)obj;
504    
505                            if ((_companyId == repositoryDirKey._companyId) &&
506                                    (_repositoryId == repositoryDirKey._repositoryId)) {
507    
508                                    return true;
509                            }
510                            else {
511                                    return false;
512                            }
513                    }
514    
515                    @Override
516                    public int hashCode() {
517                            return (int)(_companyId * 11 + _repositoryId);
518                    }
519    
520                    private long _companyId;
521                    private long _repositoryId;
522    
523            }
524    
525    }