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.document.library.kernel.store;
016    
017    import com.liferay.document.library.kernel.exception.NoSuchFileException;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.util.FileUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.Validator;
027    
028    import java.io.File;
029    import java.io.FileInputStream;
030    import java.io.FileNotFoundException;
031    import java.io.IOException;
032    import java.io.InputStream;
033    
034    /**
035     * The abstract base class for all file store implementations. Most, if not all
036     * implementations should extend this class.
037     *
038     * @author Brian Wing Shun Chan
039     * @author Alexander Chow
040     * @author Edward Han
041     */
042    public abstract class BaseStore implements Store {
043    
044            /**
045             * Adds a directory.
046             *
047             * @param companyId the primary key of the company
048             * @param repositoryId the primary key of the data repository (optionally
049             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
050             * @param dirName the directory's name
051             */
052            @Override
053            public abstract void addDirectory(
054                    long companyId, long repositoryId, String dirName);
055    
056            /**
057             * Adds a file based on a byte array.
058             *
059             * @param companyId the primary key of the company
060             * @param repositoryId the primary key of the data repository (optionally
061             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
062             * @param fileName the file name
063             * @param bytes the files's data
064             */
065            @Override
066            public void addFile(
067                            long companyId, long repositoryId, String fileName, byte[] bytes)
068                    throws PortalException {
069    
070                    try (UnsyncByteArrayInputStream unsyncByteArrayInputStream =
071                                    new UnsyncByteArrayInputStream(bytes)) {
072    
073                            addFile(
074                                    companyId, repositoryId, fileName, unsyncByteArrayInputStream);
075                    }
076                    catch (IOException ioe) {
077                            throw new SystemException("Unable to read bytes", ioe);
078                    }
079            }
080    
081            /**
082             * Adds a file based on a {@link File} object.
083             *
084             * @param companyId the primary key of the company
085             * @param repositoryId the primary key of the data repository (optionally
086             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
087             * @param fileName the file name
088             * @param file Name the file name
089             */
090            @Override
091            public void addFile(
092                            long companyId, long repositoryId, String fileName, File file)
093                    throws PortalException {
094    
095                    try (InputStream is = new FileInputStream(file)) {
096                            addFile(companyId, repositoryId, fileName, is);
097                    }
098                    catch (FileNotFoundException fnfe) {
099                            throw new SystemException(fnfe);
100                    }
101                    catch (IOException ioe) {
102                            _log.error(ioe);
103                    }
104            }
105    
106            /**
107             * Adds a file based on an {@link InputStream} object.
108             *
109             * @param companyId the primary key of the company
110             * @param repositoryId the primary key of the data repository (optionally
111             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
112             * @param fileName the file name
113             * @param is the files's data
114             */
115            @Override
116            public abstract void addFile(
117                            long companyId, long repositoryId, String fileName, InputStream is)
118                    throws PortalException;
119    
120            /**
121             * Ensures company's root directory exists. Only implemented by {@link
122             * JCRStore#checkRoot(long)}.
123             *
124             * @param companyId the primary key of the company
125             */
126            @Override
127            public abstract void checkRoot(long companyId);
128    
129            /**
130             * Creates a new copy of the file version.
131             *
132             * <p>
133             * This method should be overrided if a more optimized approach can be used
134             * (e.g., {@link FileSystemStore#copyFileVersion(long, long, String, String,
135             * String)}).
136             * </p>
137             *
138             * @param companyId the primary key of the company
139             * @param repositoryId the primary key of the data repository (optionally
140             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
141             * @param fileName the original's file name
142             * @param fromVersionLabel the original file's version label
143             * @param toVersionLabel the new version label
144             */
145            @Override
146            public void copyFileVersion(
147                            long companyId, long repositoryId, String fileName,
148                            String fromVersionLabel, String toVersionLabel)
149                    throws PortalException {
150    
151                    InputStream is = getFileAsStream(
152                            companyId, repositoryId, fileName, fromVersionLabel);
153    
154                    if (is == null) {
155                            is = new UnsyncByteArrayInputStream(new byte[0]);
156                    }
157    
158                    updateFile(companyId, repositoryId, fileName, toVersionLabel, is);
159            }
160    
161            /**
162             * Deletes a directory.
163             *
164             * @param companyId the primary key of the company
165             * @param repositoryId the primary key of the data repository (optionally
166             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
167             * @param dirName the directory's name
168             */
169            @Override
170            public abstract void deleteDirectory(
171                    long companyId, long repositoryId, String dirName);
172    
173            /**
174             * Deletes a file. If a file has multiple versions, all versions will be
175             * deleted.
176             *
177             * @param companyId the primary key of the company
178             * @param repositoryId the primary key of the data repository (optionally
179             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
180             * @param fileName the file's name
181             */
182            @Override
183            public abstract void deleteFile(
184                    long companyId, long repositoryId, String fileName);
185    
186            /**
187             * Deletes a file at a particular version.
188             *
189             * @param companyId the primary key of the company
190             * @param repositoryId the primary key of the data repository (optionally
191             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
192             * @param fileName the file's name
193             * @param versionLabel the file's version label
194             */
195            @Override
196            public abstract void deleteFile(
197                    long companyId, long repositoryId, String fileName,
198                    String versionLabel);
199    
200            /**
201             * Returns the file as a {@link File} object.
202             *
203             * <p>
204             * This method is useful when optimizing low-level file operations like
205             * copy. The client must not delete or change the returned {@link File}
206             * object in any way. This method is only supported in certain stores. If
207             * not supported, this method will throw an {@link
208             * UnsupportedOperationException}.
209             * </p>
210             *
211             * @param  companyId the primary key of the company
212             * @param  repositoryId the primary key of the data repository (optionally
213             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
214             * @param  fileName the file's name
215             * @return Returns the {@link File} object with the file's name
216             */
217            @Override
218            public File getFile(long companyId, long repositoryId, String fileName)
219                    throws PortalException {
220    
221                    return getFile(companyId, repositoryId, fileName, StringPool.BLANK);
222            }
223    
224            /**
225             * Returns the file as a {@link File} object.
226             *
227             * <p>
228             * This method is useful when optimizing low-level file operations like
229             * copy. The client must not delete or change the returned {@link File}
230             * object in any way. This method is only supported in certain stores. If
231             * not supported, this method will throw an {@link
232             * UnsupportedOperationException}.
233             * </p>
234             *
235             * <p>
236             * This method should be overrided if a more optimized approach can be used
237             * (e.g., {@link FileSystemStore#getFile(long, long, String, String)}).
238             * </p>
239             *
240             * @param  companyId the primary key of the company
241             * @param  repositoryId the primary key of the data repository (optionally
242             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
243             * @param  fileName the file's name
244             * @param  versionLabel the file's version label
245             * @return Returns the {@link File} object with the file's name
246             * @throws PortalException
247             */
248            @Override
249            public File getFile(
250                            long companyId, long repositoryId, String fileName,
251                            String versionLabel)
252                    throws PortalException {
253    
254                    throw new UnsupportedOperationException();
255            }
256    
257            /**
258             * Returns the file as a byte array.
259             *
260             * @param  companyId the primary key of the company
261             * @param  repositoryId the primary key of the data repository (optionally
262             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
263             * @param  fileName the file's name
264             * @return Returns the byte array with the file's name
265             */
266            @Override
267            public byte[] getFileAsBytes(
268                            long companyId, long repositoryId, String fileName)
269                    throws PortalException {
270    
271                    try {
272                            InputStream is = getFileAsStream(companyId, repositoryId, fileName);
273    
274                            return FileUtil.getBytes(is);
275                    }
276                    catch (IOException ioe) {
277                            throw new SystemException(ioe);
278                    }
279            }
280    
281            /**
282             * Returns the file as a byte array.
283             *
284             * @param  companyId the primary key of the company
285             * @param  repositoryId the primary key of the data repository (optionally
286             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
287             * @param  fileName the file's name
288             * @param  versionLabel the file's version label
289             * @return Returns the byte array with the file's name
290             */
291            @Override
292            public byte[] getFileAsBytes(
293                            long companyId, long repositoryId, String fileName,
294                            String versionLabel)
295                    throws PortalException {
296    
297                    try {
298                            InputStream is = getFileAsStream(
299                                    companyId, repositoryId, fileName, versionLabel);
300    
301                            return FileUtil.getBytes(is);
302                    }
303                    catch (IOException ioe) {
304                            throw new SystemException(ioe);
305                    }
306            }
307    
308            /**
309             * Returns the file as an {@link InputStream} object.
310             *
311             * @param  companyId the primary key of the company
312             * @param  repositoryId the primary key of the data repository (optionally
313             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
314             * @param  fileName the file's name
315             * @return Returns the {@link InputStream} object with the file's name
316             */
317            @Override
318            public InputStream getFileAsStream(
319                            long companyId, long repositoryId, String fileName)
320                    throws PortalException {
321    
322                    return getFileAsStream(
323                            companyId, repositoryId, fileName, StringPool.BLANK);
324            }
325    
326            /**
327             * Returns the file as an {@link InputStream} object.
328             *
329             * @param  companyId the primary key of the company
330             * @param  repositoryId the primary key of the data repository (optionally
331             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
332             * @param  fileName the file's name
333             * @param  versionLabel the file's version label
334             * @return Returns the {@link InputStream} object with the file's name
335             */
336            @Override
337            public abstract InputStream getFileAsStream(
338                            long companyId, long repositoryId, String fileName,
339                            String versionLabel)
340                    throws PortalException;
341    
342            /**
343             * Returns all files of the directory.
344             *
345             * @param  companyId the primary key of the company
346             * @param  repositoryId the primary key of the data repository (optionally
347             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
348             * @param  dirName the directory's name
349             * @return Returns all files of the directory
350             */
351            @Override
352            public abstract String[] getFileNames(
353                    long companyId, long repositoryId, String dirName);
354    
355            /**
356             * Returns the size of the file.
357             *
358             * @param  companyId the primary key of the company
359             * @param  repositoryId the primary key of the data repository (optionally
360             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
361             * @param  fileName the file's name
362             * @return Returns the size of the file
363             */
364            @Override
365            public abstract long getFileSize(
366                            long companyId, long repositoryId, String fileName)
367                    throws PortalException;
368    
369            /**
370             * Returns <code>true</code> if the directory exists.
371             *
372             * @param  companyId the primary key of the company
373             * @param  repositoryId the primary key of the data repository (optionally
374             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
375             * @param  dirName the directory's name
376             * @return <code>true</code> if the directory exists; <code>false</code>
377             *         otherwise
378             */
379            @Override
380            public abstract boolean hasDirectory(
381                    long companyId, long repositoryId, String dirName);
382    
383            /**
384             * Returns <code>true</code> if the file exists.
385             *
386             * @param  companyId the primary key of the company
387             * @param  repositoryId the primary key of the data repository (optionally
388             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
389             * @param  fileName the file's name
390             * @return <code>true</code> if the file exists; <code>false</code>
391             *         otherwise
392             */
393            @Override
394            public boolean hasFile(long companyId, long repositoryId, String fileName) {
395                    return hasFile(companyId, repositoryId, fileName, VERSION_DEFAULT);
396            }
397    
398            /**
399             * Returns <code>true</code> if the file exists.
400             *
401             * @param  companyId the primary key of the company
402             * @param  repositoryId the primary key of the data repository (optionally
403             *         {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
404             * @param  fileName the file's name
405             * @param  versionLabel the file's version label
406             * @return <code>true</code> if the file exists; <code>false</code>
407             *         otherwise
408             */
409            @Override
410            public abstract boolean hasFile(
411                    long companyId, long repositoryId, String fileName,
412                    String versionLabel);
413    
414            /**
415             * Moves an existing directory. Only implemented by {@link
416             * JCRStore#move(String, String)}.
417             *
418             * @param srcDir the original directory's name
419             * @param destDir the new directory's name
420             */
421            @Override
422            public void move(String srcDir, String destDir) {
423            }
424    
425            /**
426             * Moves a file to a new data repository.
427             *
428             * @param companyId the primary key of the company
429             * @param repositoryId the primary key of the data repository
430             * @param newRepositoryId the primary key of the new data repository
431             * @param fileName the file's name
432             */
433            @Override
434            public abstract void updateFile(
435                            long companyId, long repositoryId, long newRepositoryId,
436                            String fileName)
437                    throws PortalException;
438    
439            /**
440             * Updates a file based on a byte array.
441             *
442             * @param companyId the primary key of the company
443             * @param repositoryId the primary key of the data repository (optionally
444             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
445             * @param fileName the file name
446             * @param versionLabel the file's new version label
447             * @param bytes the new file's data
448             */
449            @Override
450            public void updateFile(
451                            long companyId, long repositoryId, String fileName,
452                            String versionLabel, byte[] bytes)
453                    throws PortalException {
454    
455                    try (UnsyncByteArrayInputStream unsyncByteArrayInputStream =
456                                    new UnsyncByteArrayInputStream(bytes)) {
457    
458                            updateFile(
459                                    companyId, repositoryId, fileName, versionLabel,
460                                    unsyncByteArrayInputStream);
461                    }
462                    catch (IOException ioe) {
463                            throw new SystemException("Unable to read bytes", ioe);
464                    }
465            }
466    
467            /**
468             * Updates a file based on a {@link File} object.
469             *
470             * @param companyId the primary key of the company
471             * @param repositoryId the primary key of the data repository (optionally
472             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
473             * @param fileName the file name
474             * @param versionLabel the file's new version label
475             * @param file Name the file name
476             */
477            @Override
478            public void updateFile(
479                            long companyId, long repositoryId, String fileName,
480                            String versionLabel, File file)
481                    throws PortalException {
482    
483                    try (InputStream is = new FileInputStream(file)) {
484                            updateFile(companyId, repositoryId, fileName, versionLabel, is);
485                    }
486                    catch (FileNotFoundException fnfe) {
487                            throw new NoSuchFileException(
488                                    companyId, repositoryId, fileName, versionLabel, fnfe);
489                    }
490                    catch (IOException ioe) {
491                            _log.error(ioe);
492                    }
493            }
494    
495            /**
496             * Updates a file based on an {@link InputStream} object.
497             *
498             * @param companyId the primary key of the company
499             * @param repositoryId the primary key of the data repository (optionally
500             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
501             * @param fileName the file name
502             * @param versionLabel the file's new version label
503             * @param is the new file's data
504             */
505            @Override
506            public abstract void updateFile(
507                            long companyId, long repositoryId, String fileName,
508                            String versionLabel, InputStream is)
509                    throws PortalException;
510    
511            /**
512             * Update's a file version label. Similar to {@link #copyFileVersion(long,
513             * long, String, String, String)} except that the old file version is
514             * deleted.
515             *
516             * @param companyId the primary key of the company
517             * @param repositoryId the primary key of the data repository (optionally
518             *        {@link com.liferay.portal.kernel.model.CompanyConstants#SYSTEM})
519             * @param fileName the file's name
520             * @param fromVersionLabel the file's version label
521             * @param toVersionLabel the file's new version label
522             */
523            @Override
524            public void updateFileVersion(
525                            long companyId, long repositoryId, String fileName,
526                            String fromVersionLabel, String toVersionLabel)
527                    throws PortalException {
528    
529                    InputStream is = getFileAsStream(
530                            companyId, repositoryId, fileName, fromVersionLabel);
531    
532                    if (is == null) {
533                            is = new UnsyncByteArrayInputStream(new byte[0]);
534                    }
535    
536                    updateFile(companyId, repositoryId, fileName, toVersionLabel, is);
537    
538                    deleteFile(companyId, repositoryId, fileName, fromVersionLabel);
539            }
540    
541            protected void logFailedDeletion(
542                    long companyId, long repositoryId, String fileName) {
543    
544                    logFailedDeletion(companyId, repositoryId, fileName, null, null);
545            }
546    
547            protected void logFailedDeletion(
548                    long companyId, long repositoryId, String fileName,
549                    Exception exception) {
550    
551                    logFailedDeletion(companyId, repositoryId, fileName, null, exception);
552            }
553    
554            protected void logFailedDeletion(
555                    long companyId, long repositoryId, String fileName,
556                    String versionLabel) {
557    
558                    logFailedDeletion(
559                            companyId, repositoryId, fileName, versionLabel, null);
560            }
561    
562            protected void logFailedDeletion(
563                    long companyId, long repositoryId, String fileName, String versionLabel,
564                    Exception cause) {
565    
566                    if ((_log.isWarnEnabled() && (cause != null)) ||
567                            (_log.isDebugEnabled() && (cause == null))) {
568    
569                            StringBundler sb = new StringBundler(9);
570    
571                            sb.append("Unable to delete file {companyId=");
572                            sb.append(companyId);
573                            sb.append(", repositoryId=");
574                            sb.append(repositoryId);
575                            sb.append(", fileName=");
576                            sb.append(fileName);
577    
578                            if (Validator.isNotNull(versionLabel)) {
579                                    sb.append(", versionLabel=");
580                                    sb.append(versionLabel);
581                            }
582    
583                            sb.append("} because it does not exist");
584    
585                            if (_log.isWarnEnabled() && (cause != null)) {
586                                    _log.warn(sb.toString(), cause);
587                            }
588    
589                            if (_log.isDebugEnabled() && (cause == null)) {
590                                    _log.debug(sb.toString());
591                            }
592                    }
593            }
594    
595            private static final Log _log = LogFactoryUtil.getLog(BaseStore.class);
596    
597    }