001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
019    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
023    import com.liferay.portal.kernel.process.ClassPathUtil;
024    import com.liferay.portal.kernel.process.ProcessCallable;
025    import com.liferay.portal.kernel.process.ProcessException;
026    import com.liferay.portal.kernel.process.ProcessExecutor;
027    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.CharPool;
030    import com.liferay.portal.kernel.util.Digester;
031    import com.liferay.portal.kernel.util.DigesterUtil;
032    import com.liferay.portal.kernel.util.FileComparator;
033    import com.liferay.portal.kernel.util.ReflectionUtil;
034    import com.liferay.portal.kernel.util.StreamUtil;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.SystemProperties;
039    import com.liferay.portal.kernel.util.Time;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.util.PwdGenerator;
042    import com.liferay.util.ant.ExpandTask;
043    
044    import java.io.File;
045    import java.io.FileInputStream;
046    import java.io.FileOutputStream;
047    import java.io.FileReader;
048    import java.io.IOException;
049    import java.io.InputStream;
050    import java.io.OutputStreamWriter;
051    import java.io.RandomAccessFile;
052    import java.io.Reader;
053    import java.io.Writer;
054    
055    import java.nio.ByteBuffer;
056    import java.nio.channels.FileChannel;
057    
058    import java.util.ArrayList;
059    import java.util.Arrays;
060    import java.util.List;
061    import java.util.Properties;
062    import java.util.concurrent.Future;
063    
064    import org.apache.commons.compress.archivers.zip.UnsupportedZipFeatureException;
065    import org.apache.commons.io.FileUtils;
066    import org.apache.commons.lang.exception.ExceptionUtils;
067    import org.apache.pdfbox.exceptions.CryptographyException;
068    import org.apache.poi.EncryptedDocumentException;
069    import org.apache.tika.Tika;
070    import org.apache.tika.exception.TikaException;
071    import org.apache.tools.ant.DirectoryScanner;
072    
073    import org.mozilla.intl.chardet.nsDetector;
074    import org.mozilla.intl.chardet.nsPSMDetector;
075    
076    /**
077     * @author Brian Wing Shun Chan
078     * @author Alexander Chow
079     */
080    @DoPrivileged
081    public class FileImpl implements com.liferay.portal.kernel.util.File {
082    
083            public static FileImpl getInstance() {
084                    return _instance;
085            }
086    
087            @Override
088            public String appendParentheticalSuffix(String fileName, String suffix) {
089                    String fileNameWithoutExtension = stripExtension(fileName);
090    
091                    String fileNameWithParentheticalSuffix =
092                            StringUtil.appendParentheticalSuffix(
093                                    fileNameWithoutExtension, suffix);
094    
095                    String extension = getExtension(fileName);
096    
097                    if (Validator.isNull(extension)) {
098                            return fileNameWithParentheticalSuffix;
099                    }
100    
101                    StringBundler sb = new StringBundler(3);
102    
103                    sb.append(fileNameWithParentheticalSuffix);
104                    sb.append(StringPool.PERIOD);
105                    sb.append(extension);
106    
107                    return sb.toString();
108            }
109    
110            @Override
111            public void copyDirectory(File source, File destination)
112                    throws IOException {
113    
114                    if (!source.exists() || !source.isDirectory()) {
115                            return;
116                    }
117    
118                    mkdirs(destination);
119    
120                    File[] fileArray = source.listFiles();
121    
122                    for (int i = 0; i < fileArray.length; i++) {
123                            if (fileArray[i].isDirectory()) {
124                                    copyDirectory(
125                                            fileArray[i],
126                                            new File(
127                                                    destination.getPath() + File.separator +
128                                                            fileArray[i].getName()));
129                            }
130                            else {
131                                    copyFile(
132                                            fileArray[i],
133                                            new File(
134                                                    destination.getPath() + File.separator +
135                                                            fileArray[i].getName()));
136                            }
137                    }
138            }
139    
140            @Override
141            public void copyDirectory(String sourceDirName, String destinationDirName)
142                    throws IOException {
143    
144                    copyDirectory(new File(sourceDirName), new File(destinationDirName));
145            }
146    
147            @Override
148            public void copyFile(File source, File destination) throws IOException {
149                    copyFile(source, destination, false);
150            }
151    
152            @Override
153            public void copyFile(File source, File destination, boolean lazy)
154                    throws IOException {
155    
156                    if (!source.exists()) {
157                            return;
158                    }
159    
160                    if (lazy) {
161                            String oldContent = null;
162    
163                            try {
164                                    oldContent = read(source);
165                            }
166                            catch (Exception e) {
167                                    return;
168                            }
169    
170                            String newContent = null;
171    
172                            try {
173                                    newContent = read(destination);
174                            }
175                            catch (Exception e) {
176                            }
177    
178                            if ((oldContent == null) || !oldContent.equals(newContent)) {
179                                    copyFile(source, destination, false);
180                            }
181                    }
182                    else {
183                            mkdirsParentFile(destination);
184    
185                            StreamUtil.transfer(
186                                    new FileInputStream(source), new FileOutputStream(destination));
187                    }
188            }
189    
190            @Override
191            public void copyFile(String source, String destination) throws IOException {
192                    copyFile(source, destination, false);
193            }
194    
195            @Override
196            public void copyFile(String source, String destination, boolean lazy)
197                    throws IOException {
198    
199                    copyFile(new File(source), new File(destination), lazy);
200            }
201    
202            @Override
203            public File createTempFile() {
204                    return createTempFile(StringPool.BLANK);
205            }
206    
207            @Override
208            public File createTempFile(byte[] bytes) throws IOException {
209                    File file = createTempFile(StringPool.BLANK);
210    
211                    write(file, bytes, false);
212    
213                    return file;
214            }
215    
216            @Override
217            public File createTempFile(InputStream is) throws IOException {
218                    File file = createTempFile(StringPool.BLANK);
219    
220                    write(file, is);
221    
222                    return file;
223            }
224    
225            @Override
226            public File createTempFile(String extension) {
227                    return new File(createTempFileName(extension));
228            }
229    
230            @Override
231            public File createTempFile(String prefix, String extension) {
232                    return new File(createTempFileName(prefix, extension));
233            }
234    
235            @Override
236            public String createTempFileName() {
237                    return createTempFileName(null, null);
238            }
239    
240            @Override
241            public String createTempFileName(String extension) {
242                    return createTempFileName(null, extension);
243            }
244    
245            @Override
246            public String createTempFileName(String prefix, String extension) {
247                    StringBundler sb = new StringBundler();
248    
249                    sb.append(SystemProperties.get(SystemProperties.TMP_DIR));
250                    sb.append(StringPool.SLASH);
251    
252                    if (Validator.isNotNull(prefix)) {
253                            sb.append(prefix);
254                    }
255    
256                    sb.append(Time.getTimestamp());
257                    sb.append(PwdGenerator.getPassword(8, PwdGenerator.KEY2));
258    
259                    if (Validator.isFileExtension(extension)) {
260                            sb.append(StringPool.PERIOD);
261                            sb.append(extension);
262                    }
263    
264                    return sb.toString();
265            }
266    
267            @Override
268            public File createTempFolder() throws IOException {
269                    File file = new File(createTempFileName());
270    
271                    mkdirs(file);
272    
273                    return file;
274            }
275    
276            @Override
277            public String decodeSafeFileName(String fileName) {
278                    return StringUtil.replace(
279                            fileName, _SAFE_FILE_NAME_2, _SAFE_FILE_NAME_1);
280            }
281    
282            @Override
283            public boolean delete(File file) {
284                    if (file != null) {
285                            boolean exists = true;
286    
287                            try {
288                                    exists = file.exists();
289                            }
290                            catch (SecurityException se) {
291    
292                                    // We may have the permission to delete a specific file without
293                                    // having the permission to check if the file exists
294    
295                            }
296    
297                            if (exists) {
298                                    return file.delete();
299                            }
300                    }
301    
302                    return false;
303            }
304    
305            @Override
306            public boolean delete(String file) {
307                    return delete(new File(file));
308            }
309    
310            @Override
311            public void deltree(File directory) {
312                    if (directory.exists() && directory.isDirectory()) {
313                            File[] fileArray = directory.listFiles();
314    
315                            for (int i = 0; i < fileArray.length; i++) {
316                                    if (fileArray[i].isDirectory()) {
317                                            deltree(fileArray[i]);
318                                    }
319                                    else {
320                                            fileArray[i].delete();
321                                    }
322                            }
323    
324                            directory.delete();
325                    }
326            }
327    
328            @Override
329            public void deltree(String directory) {
330                    deltree(new File(directory));
331            }
332    
333            @Override
334            public String encodeSafeFileName(String fileName) {
335                    if (fileName == null) {
336                            return StringPool.BLANK;
337                    }
338    
339                    return StringUtil.replace(
340                            fileName, _SAFE_FILE_NAME_1, _SAFE_FILE_NAME_2);
341            }
342    
343            @Override
344            public boolean exists(File file) {
345                    return file.exists();
346            }
347    
348            @Override
349            public boolean exists(String fileName) {
350                    return exists(new File(fileName));
351            }
352    
353            @Override
354            public String extractText(InputStream is, String fileName) {
355                    return extractText(is, fileName, -1);
356            }
357    
358            @Override
359            public String extractText(
360                    InputStream is, String fileName, int maxStringLength) {
361    
362                    if (maxStringLength == 0) {
363                            return StringPool.BLANK;
364                    }
365    
366                    String text = null;
367    
368                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
369    
370                    ClassLoader contextClassLoader =
371                            ClassLoaderUtil.getContextClassLoader();
372    
373                    try {
374                            if (contextClassLoader != portalClassLoader) {
375                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
376                            }
377    
378                            Tika tika = new Tika();
379    
380                            tika.setMaxStringLength(maxStringLength);
381    
382                            boolean forkProcess = false;
383    
384                            if (PropsValues.TEXT_EXTRACTION_FORK_PROCESS_ENABLED) {
385                                    String mimeType = tika.detect(is);
386    
387                                    if (ArrayUtil.contains(
388                                                    PropsValues.TEXT_EXTRACTION_FORK_PROCESS_MIME_TYPES,
389                                                    mimeType)) {
390    
391                                            forkProcess = true;
392                                    }
393                            }
394    
395                            if (forkProcess) {
396                                    Future<String> future = ProcessExecutor.execute(
397                                            ClassPathUtil.getPortalClassPath(),
398                                            new ExtractTextProcessCallable(getBytes(is)));
399    
400                                    text = future.get();
401                            }
402                            else {
403                                    text = tika.parseToString(is);
404                            }
405                    }
406                    catch (Exception e) {
407                            Throwable throwable = ExceptionUtils.getRootCause(e);
408    
409                            if ((throwable instanceof CryptographyException) ||
410                                    (throwable instanceof EncryptedDocumentException) ||
411                                    (throwable instanceof UnsupportedZipFeatureException)) {
412    
413                                    if (_log.isWarnEnabled()) {
414                                            _log.warn(
415                                                    "Unable to extract text from an encrypted file " +
416                                                            fileName,
417                                                    e);
418                                    }
419                            }
420                            else if (e instanceof TikaException) {
421                                    if (_log.isWarnEnabled()) {
422                                            _log.warn("Unable to extract text from " + fileName, e);
423                                    }
424                            }
425                            else {
426                                    _log.error(e, e);
427                            }
428                    }
429                    finally {
430                            if (contextClassLoader != portalClassLoader) {
431                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
432                            }
433                    }
434    
435                    if (_log.isInfoEnabled()) {
436                            if (text == null) {
437                                    _log.info("Text extraction failed for " + fileName);
438                            }
439                            else {
440                                    _log.info("Text was extracted for " + fileName);
441                            }
442                    }
443    
444                    if (_log.isDebugEnabled()) {
445                            _log.debug("Extractor returned text:\n\n" + text);
446                    }
447    
448                    if (text == null) {
449                            text = StringPool.BLANK;
450                    }
451    
452                    return text;
453            }
454    
455            @Override
456            public String[] find(String directory, String includes, String excludes) {
457                    if (directory.length() > 0) {
458                            directory = replaceSeparator(directory);
459    
460                            if (directory.charAt(directory.length() - 1) == CharPool.SLASH) {
461                                    directory = directory.substring(0, directory.length() - 1);
462                            }
463                    }
464    
465                    if (!exists(directory)) {
466                            if (_log.isWarnEnabled()) {
467                                    _log.warn("Directory " + directory + " does not exist");
468                            }
469    
470                            return new String[0];
471                    }
472    
473                    DirectoryScanner directoryScanner = new DirectoryScanner();
474    
475                    directoryScanner.setBasedir(directory);
476                    directoryScanner.setExcludes(StringUtil.split(excludes));
477                    directoryScanner.setIncludes(StringUtil.split(includes));
478    
479                    directoryScanner.scan();
480    
481                    String[] includedFiles = directoryScanner.getIncludedFiles();
482    
483                    for (int i = 0; i < includedFiles.length; i++) {
484                            includedFiles[i] = directory.concat(
485                                    StringPool.SLASH).concat(replaceSeparator(includedFiles[i]));
486                    }
487    
488                    return includedFiles;
489            }
490    
491            @Override
492            public String getAbsolutePath(File file) {
493                    return StringUtil.replace(
494                            file.getAbsolutePath(), CharPool.BACK_SLASH, CharPool.SLASH);
495            }
496    
497            @Override
498            public byte[] getBytes(File file) throws IOException {
499                    if ((file == null) || !file.exists()) {
500                            return null;
501                    }
502    
503                    RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
504    
505                    byte[] bytes = new byte[(int)randomAccessFile.length()];
506    
507                    randomAccessFile.readFully(bytes);
508    
509                    randomAccessFile.close();
510    
511                    return bytes;
512            }
513    
514            @Override
515            public byte[] getBytes(InputStream is) throws IOException {
516                    return getBytes(is, -1);
517            }
518    
519            @Override
520            public byte[] getBytes(InputStream inputStream, int bufferSize)
521                    throws IOException {
522    
523                    return getBytes(inputStream, bufferSize, true);
524            }
525    
526            @Override
527            public byte[] getBytes(
528                            InputStream inputStream, int bufferSize, boolean cleanUpStream)
529                    throws IOException {
530    
531                    if (inputStream == null) {
532                            return null;
533                    }
534    
535                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
536                            new UnsyncByteArrayOutputStream();
537    
538                    StreamUtil.transfer(
539                            inputStream, unsyncByteArrayOutputStream, bufferSize,
540                            cleanUpStream);
541    
542                    return unsyncByteArrayOutputStream.toByteArray();
543            }
544    
545            @Override
546            public String getExtension(String fileName) {
547                    if (fileName == null) {
548                            return null;
549                    }
550    
551                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
552    
553                    if (pos > 0) {
554                            return StringUtil.toLowerCase(
555                                    fileName.substring(pos + 1, fileName.length()));
556                    }
557                    else {
558                            return StringPool.BLANK;
559                    }
560            }
561    
562            @Override
563            public String getMD5Checksum(File file) throws IOException {
564                    FileInputStream fileInputStream = null;
565    
566                    try {
567                            fileInputStream = new FileInputStream(file);
568    
569                            return DigesterUtil.digestHex(Digester.MD5, fileInputStream);
570                    }
571                    finally {
572                            StreamUtil.cleanUp(fileInputStream);
573                    }
574            }
575    
576            @Override
577            public String getPath(String fullFileName) {
578                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
579                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
580    
581                    if ((x == -1) && (y == -1)) {
582                            return StringPool.SLASH;
583                    }
584    
585                    String shortFileName = fullFileName.substring(0, Math.max(x, y));
586    
587                    return shortFileName;
588            }
589    
590            @Override
591            public String getShortFileName(String fullFileName) {
592                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
593                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
594    
595                    String shortFileName = fullFileName.substring(Math.max(x, y) + 1);
596    
597                    return shortFileName;
598            }
599    
600            @Override
601            public boolean isAscii(File file) throws IOException {
602                    boolean ascii = true;
603    
604                    nsDetector detector = new nsDetector(nsPSMDetector.ALL);
605    
606                    InputStream inputStream = new FileInputStream(file);
607    
608                    byte[] buffer = new byte[1024];
609    
610                    int len = 0;
611    
612                    while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
613                            if (ascii) {
614                                    ascii = detector.isAscii(buffer, len);
615    
616                                    if (!ascii) {
617                                            break;
618                                    }
619                            }
620                    }
621    
622                    detector.DataEnd();
623    
624                    inputStream.close();
625    
626                    return ascii;
627            }
628    
629            @Override
630            public boolean isSameContent(File file, byte[] bytes, int length) {
631                    FileChannel fileChannel = null;
632    
633                    try {
634                            FileInputStream fileInputStream = new FileInputStream(file);
635    
636                            fileChannel = fileInputStream.getChannel();
637    
638                            if (fileChannel.size() != length) {
639                                    return false;
640                            }
641    
642                            byte[] buffer = new byte[1024];
643    
644                            ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
645    
646                            int bufferIndex = 0;
647                            int bufferLength = -1;
648    
649                            while (((bufferLength = fileChannel.read(byteBuffer)) > 0) &&
650                                       (bufferIndex < length)) {
651    
652                                    for (int i = 0; i < bufferLength; i++) {
653                                            if (buffer[i] != bytes[bufferIndex++]) {
654                                                    return false;
655                                            }
656                                    }
657    
658                                    byteBuffer.clear();
659                            }
660    
661                            if ((bufferIndex != length) || (bufferLength != -1)) {
662                                    return false;
663                            }
664                            else {
665                                    return true;
666                            }
667                    }
668                    catch (Exception e) {
669                            return false;
670                    }
671                    finally {
672                            if (fileChannel != null) {
673                                    try {
674                                            fileChannel.close();
675                                    }
676                                    catch (IOException ioe) {
677                                    }
678                            }
679                    }
680            }
681    
682            @Override
683            public boolean isSameContent(File file, String s) {
684                    ByteBuffer byteBuffer = CharsetEncoderUtil.encode(StringPool.UTF8, s);
685    
686                    return isSameContent(file, byteBuffer.array(), byteBuffer.limit());
687            }
688    
689            @Override
690            public String[] listDirs(File file) {
691                    List<String> dirs = new ArrayList<String>();
692    
693                    File[] fileArray = file.listFiles();
694    
695                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
696                            if (fileArray[i].isDirectory()) {
697                                    dirs.add(fileArray[i].getName());
698                            }
699                    }
700    
701                    return dirs.toArray(new String[dirs.size()]);
702            }
703    
704            @Override
705            public String[] listDirs(String fileName) {
706                    return listDirs(new File(fileName));
707            }
708    
709            @Override
710            public String[] listFiles(File file) {
711                    List<String> files = new ArrayList<String>();
712    
713                    File[] fileArray = file.listFiles();
714    
715                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
716                            if (fileArray[i].isFile()) {
717                                    files.add(fileArray[i].getName());
718                            }
719                    }
720    
721                    return files.toArray(new String[files.size()]);
722            }
723    
724            @Override
725            public String[] listFiles(String fileName) {
726                    if (Validator.isNull(fileName)) {
727                            return new String[0];
728                    }
729    
730                    return listFiles(new File(fileName));
731            }
732    
733            @Override
734            public void mkdirs(File file) throws IOException {
735                    FileUtils.forceMkdir(file);
736            }
737    
738            @Override
739            public void mkdirs(String pathName) {
740                    File file = new File(pathName);
741    
742                    if (file.exists() && file.isDirectory()) {
743                            if (_log.isDebugEnabled()) {
744                                    _log.debug("Directory " + pathName + " already exists");
745                            }
746    
747                            return;
748                    }
749    
750                    try {
751                            mkdirs(file);
752                    }
753                    catch (IOException ioe) {
754                            ReflectionUtil.throwException(ioe);
755                    }
756            }
757    
758            @Override
759            public boolean move(File source, File destination) {
760                    if (!source.exists()) {
761                            return false;
762                    }
763    
764                    destination.delete();
765    
766                    try {
767                            if (source.isDirectory()) {
768                                    FileUtils.moveDirectory(source, destination);
769                            }
770                            else {
771                                    FileUtils.moveFile(source, destination);
772                            }
773                    }
774                    catch (IOException ioe) {
775                            return false;
776                    }
777    
778                    return true;
779            }
780    
781            @Override
782            public boolean move(String sourceFileName, String destinationFileName) {
783                    return move(new File(sourceFileName), new File(destinationFileName));
784            }
785    
786            @Override
787            public String read(File file) throws IOException {
788                    return read(file, false);
789            }
790    
791            @Override
792            public String read(File file, boolean raw) throws IOException {
793                    byte[] bytes = getBytes(file);
794    
795                    if (bytes == null) {
796                            return null;
797                    }
798    
799                    String s = new String(bytes, StringPool.UTF8);
800    
801                    if (raw) {
802                            return s;
803                    }
804                    else {
805                            return StringUtil.replace(
806                                    s, StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE);
807                    }
808            }
809    
810            @Override
811            public String read(String fileName) throws IOException {
812                    return read(new File(fileName));
813            }
814    
815            @Override
816            public String replaceSeparator(String fileName) {
817                    return StringUtil.replace(
818                            fileName, CharPool.BACK_SLASH, CharPool.SLASH);
819            }
820    
821            @Override
822            public File[] sortFiles(File[] files) {
823                    if (files == null) {
824                            return null;
825                    }
826    
827                    Arrays.sort(files, new FileComparator());
828    
829                    List<File> directoryList = new ArrayList<File>();
830                    List<File> fileList = new ArrayList<File>();
831    
832                    for (int i = 0; i < files.length; i++) {
833                            if (files[i].isDirectory()) {
834                                    directoryList.add(files[i]);
835                            }
836                            else {
837                                    fileList.add(files[i]);
838                            }
839                    }
840    
841                    directoryList.addAll(fileList);
842    
843                    return directoryList.toArray(new File[directoryList.size()]);
844            }
845    
846            @Override
847            public String stripExtension(String fileName) {
848                    if (fileName == null) {
849                            return null;
850                    }
851    
852                    String ext = getExtension(fileName);
853    
854                    if (ext.length() > 0) {
855                            return fileName.substring(0, fileName.length() - ext.length() - 1);
856                    }
857                    else {
858                            return fileName;
859                    }
860            }
861    
862            @Override
863            public List<String> toList(Reader reader) {
864                    List<String> list = new ArrayList<String>();
865    
866                    try {
867                            UnsyncBufferedReader unsyncBufferedReader =
868                                    new UnsyncBufferedReader(reader);
869    
870                            String line = null;
871    
872                            while ((line = unsyncBufferedReader.readLine()) != null) {
873                                    list.add(line);
874                            }
875    
876                            unsyncBufferedReader.close();
877                    }
878                    catch (IOException ioe) {
879                    }
880    
881                    return list;
882            }
883    
884            @Override
885            public List<String> toList(String fileName) {
886                    try {
887                            return toList(new FileReader(fileName));
888                    }
889                    catch (IOException ioe) {
890                            return new ArrayList<String>();
891                    }
892            }
893    
894            @Override
895            public Properties toProperties(FileInputStream fis) {
896                    Properties properties = new Properties();
897    
898                    try {
899                            properties.load(fis);
900                    }
901                    catch (IOException ioe) {
902                    }
903    
904                    return properties;
905            }
906    
907            @Override
908            public Properties toProperties(String fileName) {
909                    try {
910                            return toProperties(new FileInputStream(fileName));
911                    }
912                    catch (IOException ioe) {
913                            return new Properties();
914                    }
915            }
916    
917            @Override
918            public void touch(File file) throws IOException {
919                    FileUtils.touch(file);
920            }
921    
922            @Override
923            public void touch(String fileName) throws IOException {
924                    touch(new File(fileName));
925            }
926    
927            @Override
928            public void unzip(File source, File destination) {
929                    ExpandTask.expand(source, destination);
930            }
931    
932            @Override
933            public void write(File file, byte[] bytes) throws IOException {
934                    write(file, bytes, 0, bytes.length, false);
935            }
936    
937            @Override
938            public void write(File file, byte[] bytes, boolean append)
939                    throws IOException {
940    
941                    write(file, bytes, 0, bytes.length, append);
942            }
943    
944            @Override
945            public void write(File file, byte[] bytes, int offset, int length)
946                    throws IOException {
947    
948                    write(file, bytes, offset, bytes.length, false);
949            }
950    
951            @Override
952            public void write(
953                            File file, byte[] bytes, int offset, int length, boolean append)
954                    throws IOException {
955    
956                    mkdirsParentFile(file);
957    
958                    FileOutputStream fileOutputStream = new FileOutputStream(file, append);
959    
960                    fileOutputStream.write(bytes, offset, length);
961    
962                    fileOutputStream.close();
963            }
964    
965            @Override
966            public void write(File file, InputStream is) throws IOException {
967                    mkdirsParentFile(file);
968    
969                    StreamUtil.transfer(is, new FileOutputStream(file));
970            }
971    
972            @Override
973            public void write(File file, String s) throws IOException {
974                    write(file, s, false);
975            }
976    
977            @Override
978            public void write(File file, String s, boolean lazy) throws IOException {
979                    write(file, s, lazy, false);
980            }
981    
982            @Override
983            public void write(File file, String s, boolean lazy, boolean append)
984                    throws IOException {
985    
986                    if (s == null) {
987                            return;
988                    }
989    
990                    mkdirsParentFile(file);
991    
992                    if (lazy && file.exists()) {
993                            String content = read(file);
994    
995                            if (content.equals(s)) {
996                                    return;
997                            }
998                    }
999    
1000                    Writer writer = new OutputStreamWriter(
1001                            new FileOutputStream(file, append), StringPool.UTF8);
1002    
1003                    writer.write(s);
1004    
1005                    writer.close();
1006            }
1007    
1008            @Override
1009            public void write(String fileName, byte[] bytes) throws IOException {
1010                    write(new File(fileName), bytes);
1011            }
1012    
1013            @Override
1014            public void write(String fileName, InputStream is) throws IOException {
1015                    write(new File(fileName), is);
1016            }
1017    
1018            @Override
1019            public void write(String fileName, String s) throws IOException {
1020                    write(new File(fileName), s);
1021            }
1022    
1023            @Override
1024            public void write(String fileName, String s, boolean lazy)
1025                    throws IOException {
1026    
1027                    write(new File(fileName), s, lazy);
1028            }
1029    
1030            @Override
1031            public void write(String fileName, String s, boolean lazy, boolean append)
1032                    throws IOException {
1033    
1034                    write(new File(fileName), s, lazy, append);
1035            }
1036    
1037            @Override
1038            public void write(String pathName, String fileName, String s)
1039                    throws IOException {
1040    
1041                    write(new File(pathName, fileName), s);
1042            }
1043    
1044            @Override
1045            public void write(String pathName, String fileName, String s, boolean lazy)
1046                    throws IOException {
1047    
1048                    write(new File(pathName, fileName), s, lazy);
1049            }
1050    
1051            @Override
1052            public void write(
1053                            String pathName, String fileName, String s, boolean lazy,
1054                            boolean append)
1055                    throws IOException {
1056    
1057                    write(new File(pathName, fileName), s, lazy, append);
1058            }
1059    
1060            protected void mkdirsParentFile(File file) throws IOException {
1061                    File parentFile = file.getParentFile();
1062    
1063                    if (parentFile == null) {
1064                            return;
1065                    }
1066    
1067                    try {
1068                            mkdirs(parentFile);
1069                    }
1070                    catch (SecurityException se) {
1071    
1072                            // We may have the permission to write a specific file without
1073                            // having the permission to check if the parent file exists
1074    
1075                    }
1076            }
1077    
1078            private static final String[] _SAFE_FILE_NAME_1 = {
1079                    StringPool.AMPERSAND, StringPool.CLOSE_PARENTHESIS,
1080                    StringPool.OPEN_PARENTHESIS, StringPool.SEMICOLON
1081            };
1082    
1083            private static final String[] _SAFE_FILE_NAME_2 = {
1084                    PropsValues.DL_STORE_FILE_IMPL_SAFE_FILE_NAME_2_AMPERSAND,
1085                    PropsValues.DL_STORE_FILE_IMPL_SAFE_FILE_NAME_2_CLOSE_PARENTHESIS,
1086                    PropsValues.DL_STORE_FILE_IMPL_SAFE_FILE_NAME_2_OPEN_PARENTHESIS,
1087                    PropsValues.DL_STORE_FILE_IMPL_SAFE_FILE_NAME_2_SEMICOLON
1088            };
1089    
1090            private static Log _log = LogFactoryUtil.getLog(FileImpl.class);
1091    
1092            private static FileImpl _instance = new FileImpl();
1093    
1094            private static class ExtractTextProcessCallable
1095                    implements ProcessCallable<String> {
1096    
1097                    public ExtractTextProcessCallable(byte[] data) {
1098                            _data = data;
1099                    }
1100    
1101                    @Override
1102                    public String call() throws ProcessException {
1103                            Tika tika = new Tika();
1104    
1105                            try {
1106                                    return tika.parseToString(
1107                                            new UnsyncByteArrayInputStream(_data));
1108                            }
1109                            catch (Exception e) {
1110                                    throw new ProcessException(e);
1111                            }
1112                    }
1113    
1114                    private static final long serialVersionUID = 1L;
1115    
1116                    private byte[] _data;
1117    
1118            }
1119    
1120    }