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