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