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