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.SystemException;
018    import com.liferay.portal.kernel.util.CharPool;
019    import com.liferay.portal.kernel.util.FileUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.util.PropsValues;
024    import com.liferay.portlet.documentlibrary.DuplicateFileException;
025    import com.liferay.portlet.documentlibrary.NoSuchFileException;
026    import com.liferay.portlet.documentlibrary.util.DLUtil;
027    
028    import java.io.File;
029    
030    import java.util.ArrayList;
031    import java.util.List;
032    import java.util.ListIterator;
033    
034    /**
035     * <p>
036     * See https://issues.liferay.com/browse/LPS-1976.
037     * </p>
038     *
039     * @author Jorge Ferrer
040     * @author Ryan Park
041     * @author Brian Wing Shun Chan
042     */
043    public class AdvancedFileSystemStore extends FileSystemStore {
044    
045            @Override
046            public void updateFile(
047                            long companyId, long repositoryId, String fileName,
048                            String newFileName)
049                    throws DuplicateFileException, NoSuchFileException {
050    
051                    super.updateFile(companyId, repositoryId, fileName, newFileName);
052    
053                    File newFileNameDir = getFileNameDir(
054                            companyId, repositoryId, newFileName);
055    
056                    String[] fileNameVersions = FileUtil.listFiles(newFileNameDir);
057    
058                    for (String fileNameVersion : fileNameVersions) {
059                            String ext = FileUtil.getExtension(fileNameVersion);
060    
061                            String newFileNameVersion = newFileName;
062    
063                            if (ext.equals(_HOOK_EXTENSION)) {
064                                    int pos = fileNameVersion.lastIndexOf(CharPool.UNDERLINE);
065    
066                                    newFileNameVersion += fileNameVersion.substring(pos);
067                            }
068    
069                            File fileNameVersionFile = new File(
070                                    newFileNameDir + StringPool.SLASH + fileNameVersion);
071    
072                            if (!fileNameVersionFile.exists()) {
073                                    throw new NoSuchFileException(
074                                            companyId, repositoryId, fileName, fileNameVersion);
075                            }
076    
077                            File newFileNameVersionFile = new File(
078                                    newFileNameDir + StringPool.SLASH + newFileNameVersion);
079    
080                            boolean renamed = FileUtil.move(
081                                    fileNameVersionFile, newFileNameVersionFile);
082    
083                            if (!renamed) {
084                                    throw new SystemException(
085                                            "File name version file was not renamed from " +
086                                                    fileNameVersionFile.getPath() + " to " +
087                                                            newFileNameVersionFile.getPath());
088                            }
089                    }
090            }
091    
092            protected void buildPath(StringBundler sb, String fileNameFragment) {
093                    int fileNameFragmentLength = fileNameFragment.length();
094    
095                    if (fileNameFragmentLength <= 2) {
096                            return;
097                    }
098    
099                    for (int i = 0; (i + 2) < fileNameFragmentLength; i += 2) {
100                            sb.append(fileNameFragment.substring(i, i + 2));
101                            sb.append(StringPool.SLASH);
102    
103                            if (getDepth(sb.toString()) > 3) {
104                                    return;
105                            }
106                    }
107            }
108    
109            /**
110             * @deprecated As of 7.0.0, replaced by {@link #getFileNames(List, String,
111             *             String)}
112             */
113            @Deprecated
114            protected List<String> getAdvancedFileNames(
115                    long companyId, long repositoryId, String fileName) {
116    
117                    List<String> fileNames = new ArrayList<>();
118    
119                    getFileNames(fileNames, StringPool.BLANK, fileName);
120    
121                    return fileNames;
122            }
123    
124            protected int getDepth(String path) {
125                    String[] fragments = StringUtil.split(path, CharPool.SLASH);
126    
127                    return fragments.length;
128            }
129    
130            @Override
131            protected File getDirNameDir(
132                    long companyId, long repositoryId, String dirName) {
133    
134                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
135    
136                    return new File(repositoryDir + StringPool.SLASH + dirName);
137            }
138    
139            @Override
140            protected File getFileNameDir(
141                    long companyId, long repositoryId, String fileName) {
142    
143                    if (fileName.indexOf(CharPool.SLASH) != -1) {
144                            return getDirNameDir(companyId, repositoryId, fileName);
145                    }
146    
147                    String ext = StringPool.PERIOD + FileUtil.getExtension(fileName);
148    
149                    if (ext.equals(StringPool.PERIOD)) {
150                            ext += _HOOK_EXTENSION;
151                    }
152    
153                    StringBundler sb = new StringBundler();
154    
155                    String fileNameFragment = FileUtil.stripExtension(fileName);
156    
157                    if (fileNameFragment.startsWith("DLFE-")) {
158                            fileNameFragment = fileNameFragment.substring(5);
159    
160                            sb.append("DLFE/");
161                    }
162    
163                    buildPath(sb, fileNameFragment);
164    
165                    File repositoryDir = getRepositoryDir(companyId, repositoryId);
166    
167                    StringBundler pathSB = new StringBundler(6);
168    
169                    pathSB.append(repositoryDir);
170                    pathSB.append(StringPool.SLASH);
171                    pathSB.append(sb.toString());
172    
173                    FileUtil.mkdirs(pathSB.toString());
174    
175                    pathSB.append(StringPool.SLASH);
176                    pathSB.append(fileNameFragment);
177                    pathSB.append(ext);
178    
179                    return new File(pathSB.toString());
180            }
181    
182            @Override
183            protected void getFileNames(
184                    List<String> fileNames, String dirName, String path) {
185    
186                    super.getFileNames(fileNames, dirName, path);
187    
188                    ListIterator<String> iterator = fileNames.listIterator();
189    
190                    while (iterator.hasNext()) {
191                            String shortFileName = iterator.next();
192    
193                            if (path.endsWith(_HOOK_EXTENSION)) {
194                                    shortFileName = FileUtil.stripExtension(shortFileName);
195                            }
196    
197                            iterator.set(unbuildPath(shortFileName));
198                    }
199            }
200    
201            @Override
202            protected File getFileNameVersionFile(
203                    long companyId, long repositoryId, String fileName, String version) {
204    
205                    String ext = StringPool.PERIOD + FileUtil.getExtension(fileName);
206    
207                    if (ext.equals(StringPool.PERIOD)) {
208                            ext += _HOOK_EXTENSION;
209                    }
210    
211                    int pos = fileName.lastIndexOf(CharPool.SLASH);
212    
213                    if (pos == -1) {
214                            StringBundler sb = new StringBundler();
215    
216                            String fileNameFragment = FileUtil.stripExtension(fileName);
217    
218                            if (fileNameFragment.startsWith("DLFE-")) {
219                                    fileNameFragment = fileNameFragment.substring(5);
220    
221                                    sb.append("DLFE/");
222                            }
223    
224                            buildPath(sb, fileNameFragment);
225    
226                            File repositoryDir = getRepositoryDir(companyId, repositoryId);
227    
228                            StringBundler pathSB = new StringBundler(11);
229    
230                            pathSB.append(repositoryDir);
231                            pathSB.append(StringPool.SLASH);
232                            pathSB.append(sb.toString());
233                            pathSB.append(StringPool.SLASH);
234                            pathSB.append(fileNameFragment);
235                            pathSB.append(ext);
236                            pathSB.append(StringPool.SLASH);
237                            pathSB.append(fileNameFragment);
238                            pathSB.append(StringPool.UNDERLINE);
239                            pathSB.append(version);
240                            pathSB.append(ext);
241    
242                            return new File(pathSB.toString());
243                    }
244                    else {
245                            File fileNameDir = getDirNameDir(companyId, repositoryId, fileName);
246    
247                            String fileNameFragment = FileUtil.stripExtension(
248                                    fileName.substring(pos + 1));
249    
250                            StringBundler pathSB = new StringBundler(6);
251    
252                            pathSB.append(fileNameDir);
253                            pathSB.append(StringPool.SLASH);
254                            pathSB.append(fileNameFragment);
255                            pathSB.append(StringPool.UNDERLINE);
256                            pathSB.append(version);
257                            pathSB.append(ext);
258    
259                            return new File(pathSB.toString());
260                    }
261            }
262    
263            @Override
264            protected String getHeadVersionLabel(
265                    long companyId, long repositoryId, String fileName) {
266    
267                    File fileNameDir = getFileNameDir(companyId, repositoryId, fileName);
268    
269                    if (!fileNameDir.exists()) {
270                            return VERSION_DEFAULT;
271                    }
272    
273                    String[] versionLabels = FileUtil.listFiles(fileNameDir);
274    
275                    String headVersionLabel = VERSION_DEFAULT;
276    
277                    for (int i = 0; i < versionLabels.length; i++) {
278                            String versionLabelFragment = versionLabels[i];
279    
280                            int x = versionLabelFragment.lastIndexOf(CharPool.UNDERLINE);
281                            int y = versionLabelFragment.lastIndexOf(CharPool.PERIOD);
282    
283                            if (x > -1) {
284                                    versionLabelFragment = versionLabelFragment.substring(x + 1, y);
285                            }
286    
287                            String versionLabel = versionLabelFragment;
288    
289                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
290                                    headVersionLabel = versionLabel;
291                            }
292                    }
293    
294                    return headVersionLabel;
295            }
296    
297            @Override
298            protected String getRootDirName() {
299                    return PropsValues.DL_STORE_ADVANCED_FILE_SYSTEM_ROOT_DIR;
300            }
301    
302            protected String unbuildPath(String path) {
303                    if (path.startsWith("DLFE/")) {
304                            path = path.substring(5);
305                    }
306    
307                    if (path.length() <= 2) {
308                            return path;
309                    }
310    
311                    String[] parts = StringUtil.split(path, CharPool.SLASH);
312    
313                    StringBundler sb = new StringBundler(parts.length - 1);
314    
315                    for (int i = 0; i < parts.length - 1; i++) {
316                            sb.append(parts[i]);
317                    }
318    
319                    String simpleName = parts[parts.length - 1];
320    
321                    if (simpleName.startsWith(sb.toString())) {
322                            return simpleName;
323                    }
324    
325                    return path;
326            }
327    
328            private static final String _HOOK_EXTENSION = "afsh";
329    
330    }