001    /**
002     * Copyright (c) 2000-2013 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.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                    String text = null;
363    
364                    ClassLoader portalClassLoader = ClassLoaderUtil.getPortalClassLoader();
365    
366                    ClassLoader contextClassLoader =
367                            ClassLoaderUtil.getContextClassLoader();
368    
369                    try {
370                            if (contextClassLoader != portalClassLoader) {
371                                    ClassLoaderUtil.setContextClassLoader(portalClassLoader);
372                            }
373    
374                            Tika tika = new Tika();
375    
376                            tika.setMaxStringLength(maxStringLength);
377    
378                            boolean forkProcess = false;
379    
380                            if (PropsValues.TEXT_EXTRACTION_FORK_PROCESS_ENABLED) {
381                                    String mimeType = tika.detect(is);
382    
383                                    if (ArrayUtil.contains(
384                                                    PropsValues.TEXT_EXTRACTION_FORK_PROCESS_MIME_TYPES,
385                                                    mimeType)) {
386    
387                                            forkProcess = true;
388                                    }
389                            }
390    
391                            if (forkProcess) {
392                                    Future<String> future = ProcessExecutor.execute(
393                                            ClassPathUtil.getPortalClassPath(),
394                                            new ExtractTextProcessCallable(getBytes(is)));
395    
396                                    text = future.get();
397                            }
398                            else {
399                                    text = tika.parseToString(is);
400                            }
401                    }
402                    catch (Exception e) {
403                            Throwable throwable = ExceptionUtils.getRootCause(e);
404    
405                            if ((throwable instanceof CryptographyException) ||
406                                    (throwable instanceof EncryptedDocumentException) ||
407                                    (throwable instanceof UnsupportedZipFeatureException)) {
408    
409                                    if (_log.isWarnEnabled()) {
410                                            _log.warn(
411                                                    "Unable to extract text from an encrypted file " +
412                                                            fileName);
413                                    }
414                            }
415                            else if (e instanceof TikaException) {
416                                    if (_log.isWarnEnabled()) {
417                                            _log.warn("Unable to extract text from " + fileName);
418                                    }
419                            }
420                            else {
421                                    _log.error(e, e);
422                            }
423                    }
424                    finally {
425                            if (contextClassLoader != portalClassLoader) {
426                                    ClassLoaderUtil.setContextClassLoader(contextClassLoader);
427                            }
428                    }
429    
430                    if (_log.isInfoEnabled()) {
431                            if (text == null) {
432                                    _log.info("Text extraction failed for " + fileName);
433                            }
434                            else {
435                                    _log.info("Text was extracted for " + fileName);
436                            }
437                    }
438    
439                    if (_log.isDebugEnabled()) {
440                            _log.debug("Extractor returned text:\n\n" + text);
441                    }
442    
443                    if (text == null) {
444                            text = StringPool.BLANK;
445                    }
446    
447                    return text;
448            }
449    
450            @Override
451            public String[] find(String directory, String includes, String excludes) {
452                    if (directory.length() > 0) {
453                            directory = replaceSeparator(directory);
454    
455                            if (directory.charAt(directory.length() - 1) == CharPool.SLASH) {
456                                    directory = directory.substring(0, directory.length() - 1);
457                            }
458                    }
459    
460                    if (!exists(directory)) {
461                            if (_log.isWarnEnabled()) {
462                                    _log.warn("Directory " + directory + " does not exist");
463                            }
464    
465                            return new String[0];
466                    }
467    
468                    DirectoryScanner directoryScanner = new DirectoryScanner();
469    
470                    directoryScanner.setBasedir(directory);
471                    directoryScanner.setExcludes(StringUtil.split(excludes));
472                    directoryScanner.setIncludes(StringUtil.split(includes));
473    
474                    directoryScanner.scan();
475    
476                    String[] includedFiles = directoryScanner.getIncludedFiles();
477    
478                    for (int i = 0; i < includedFiles.length; i++) {
479                            includedFiles[i] = directory.concat(
480                                    StringPool.SLASH).concat(replaceSeparator(includedFiles[i]));
481                    }
482    
483                    return includedFiles;
484            }
485    
486            @Override
487            public String getAbsolutePath(File file) {
488                    return StringUtil.replace(
489                            file.getAbsolutePath(), CharPool.BACK_SLASH, CharPool.SLASH);
490            }
491    
492            @Override
493            public byte[] getBytes(File file) throws IOException {
494                    if ((file == null) || !file.exists()) {
495                            return null;
496                    }
497    
498                    RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
499    
500                    byte[] bytes = new byte[(int)randomAccessFile.length()];
501    
502                    randomAccessFile.readFully(bytes);
503    
504                    randomAccessFile.close();
505    
506                    return bytes;
507            }
508    
509            @Override
510            public byte[] getBytes(InputStream is) throws IOException {
511                    return getBytes(is, -1);
512            }
513    
514            @Override
515            public byte[] getBytes(InputStream inputStream, int bufferSize)
516                    throws IOException {
517    
518                    return getBytes(inputStream, bufferSize, true);
519            }
520    
521            @Override
522            public byte[] getBytes(
523                            InputStream inputStream, int bufferSize, boolean cleanUpStream)
524                    throws IOException {
525    
526                    if (inputStream == null) {
527                            return null;
528                    }
529    
530                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
531                            new UnsyncByteArrayOutputStream();
532    
533                    StreamUtil.transfer(
534                            inputStream, unsyncByteArrayOutputStream, bufferSize,
535                            cleanUpStream);
536    
537                    return unsyncByteArrayOutputStream.toByteArray();
538            }
539    
540            @Override
541            public String getExtension(String fileName) {
542                    if (fileName == null) {
543                            return null;
544                    }
545    
546                    int pos = fileName.lastIndexOf(CharPool.PERIOD);
547    
548                    if (pos > 0) {
549                            return StringUtil.toLowerCase(
550                                    fileName.substring(pos + 1, fileName.length()));
551                    }
552                    else {
553                            return StringPool.BLANK;
554                    }
555            }
556    
557            @Override
558            public String getMD5Checksum(File file) throws IOException {
559                    FileInputStream fileInputStream = null;
560    
561                    try {
562                            fileInputStream = new FileInputStream(file);
563    
564                            return DigesterUtil.digestHex(Digester.MD5, fileInputStream);
565                    }
566                    finally {
567                            StreamUtil.cleanUp(fileInputStream);
568                    }
569            }
570    
571            @Override
572            public String getPath(String fullFileName) {
573                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
574                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
575    
576                    if ((x == -1) && (y == -1)) {
577                            return StringPool.SLASH;
578                    }
579    
580                    String shortFileName = fullFileName.substring(0, Math.max(x, y));
581    
582                    return shortFileName;
583            }
584    
585            @Override
586            public String getShortFileName(String fullFileName) {
587                    int x = fullFileName.lastIndexOf(CharPool.SLASH);
588                    int y = fullFileName.lastIndexOf(CharPool.BACK_SLASH);
589    
590                    String shortFileName = fullFileName.substring(Math.max(x, y) + 1);
591    
592                    return shortFileName;
593            }
594    
595            @Override
596            public boolean isAscii(File file) throws IOException {
597                    boolean ascii = true;
598    
599                    nsDetector detector = new nsDetector(nsPSMDetector.ALL);
600    
601                    InputStream inputStream = new FileInputStream(file);
602    
603                    byte[] buffer = new byte[1024];
604    
605                    int len = 0;
606    
607                    while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
608                            if (ascii) {
609                                    ascii = detector.isAscii(buffer, len);
610    
611                                    if (!ascii) {
612                                            break;
613                                    }
614                            }
615                    }
616    
617                    detector.DataEnd();
618    
619                    inputStream.close();
620    
621                    return ascii;
622            }
623    
624            @Override
625            public boolean isSameContent(File file, byte[] bytes, int length) {
626                    FileChannel fileChannel = null;
627    
628                    try {
629                            FileInputStream fileInputStream = new FileInputStream(file);
630    
631                            fileChannel = fileInputStream.getChannel();
632    
633                            if (fileChannel.size() != length) {
634                                    return false;
635                            }
636    
637                            byte[] buffer = new byte[1024];
638    
639                            ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
640    
641                            int bufferIndex = 0;
642                            int bufferLength = -1;
643    
644                            while (((bufferLength = fileChannel.read(byteBuffer)) > 0) &&
645                                       (bufferIndex < length)) {
646    
647                                    for (int i = 0; i < bufferLength; i++) {
648                                            if (buffer[i] != bytes[bufferIndex++]) {
649                                                    return false;
650                                            }
651                                    }
652    
653                                    byteBuffer.clear();
654                            }
655    
656                            if ((bufferIndex != length) || (bufferLength != -1)) {
657                                    return false;
658                            }
659                            else {
660                                    return true;
661                            }
662                    }
663                    catch (Exception e) {
664                            return false;
665                    }
666                    finally {
667                            if (fileChannel != null) {
668                                    try {
669                                            fileChannel.close();
670                                    }
671                                    catch (IOException ioe) {
672                                    }
673                            }
674                    }
675            }
676    
677            @Override
678            public boolean isSameContent(File file, String s) {
679                    ByteBuffer byteBuffer = CharsetEncoderUtil.encode(StringPool.UTF8, s);
680    
681                    return isSameContent(file, byteBuffer.array(), byteBuffer.limit());
682            }
683    
684            @Override
685            public String[] listDirs(File file) {
686                    List<String> dirs = new ArrayList<String>();
687    
688                    File[] fileArray = file.listFiles();
689    
690                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
691                            if (fileArray[i].isDirectory()) {
692                                    dirs.add(fileArray[i].getName());
693                            }
694                    }
695    
696                    return dirs.toArray(new String[dirs.size()]);
697            }
698    
699            @Override
700            public String[] listDirs(String fileName) {
701                    return listDirs(new File(fileName));
702            }
703    
704            @Override
705            public String[] listFiles(File file) {
706                    List<String> files = new ArrayList<String>();
707    
708                    File[] fileArray = file.listFiles();
709    
710                    for (int i = 0; (fileArray != null) && (i < fileArray.length); i++) {
711                            if (fileArray[i].isFile()) {
712                                    files.add(fileArray[i].getName());
713                            }
714                    }
715    
716                    return files.toArray(new String[files.size()]);
717            }
718    
719            @Override
720            public String[] listFiles(String fileName) {
721                    if (Validator.isNull(fileName)) {
722                            return new String[0];
723                    }
724    
725                    return listFiles(new File(fileName));
726            }
727    
728            @Override
729            public void mkdirs(File file) throws IOException {
730                    FileUtils.forceMkdir(file);
731            }
732    
733            @Override
734            public void mkdirs(String pathName) {
735                    File file = new File(pathName);
736    
737                    if (file.exists() && file.isDirectory()) {
738                            if (_log.isDebugEnabled()) {
739                                    _log.debug("Directory " + pathName + " already exists");
740                            }
741    
742                            return;
743                    }
744    
745                    try {
746                            mkdirs(file);
747                    }
748                    catch (IOException ioe) {
749                            ReflectionUtil.throwException(ioe);
750                    }
751            }
752    
753            @Override
754            public boolean move(File source, File destination) {
755                    if (!source.exists()) {
756                            return false;
757                    }
758    
759                    destination.delete();
760    
761                    try {
762                            if (source.isDirectory()) {
763                                    FileUtils.moveDirectory(source, destination);
764                            }
765                            else {
766                                    FileUtils.moveFile(source, destination);
767                            }
768                    }
769                    catch (IOException ioe) {
770                            return false;
771                    }
772    
773                    return true;
774            }
775    
776            @Override
777            public boolean move(String sourceFileName, String destinationFileName) {
778                    return move(new File(sourceFileName), new File(destinationFileName));
779            }
780    
781            @Override
782            public String read(File file) throws IOException {
783                    return read(file, false);
784            }
785    
786            @Override
787            public String read(File file, boolean raw) throws IOException {
788                    byte[] bytes = getBytes(file);
789    
790                    if (bytes == null) {
791                            return null;
792                    }
793    
794                    String s = new String(bytes, StringPool.UTF8);
795    
796                    if (raw) {
797                            return s;
798                    }
799                    else {
800                            return StringUtil.replace(
801                                    s, StringPool.RETURN_NEW_LINE, StringPool.NEW_LINE);
802                    }
803            }
804    
805            @Override
806            public String read(String fileName) throws IOException {
807                    return read(new File(fileName));
808            }
809    
810            @Override
811            public String replaceSeparator(String fileName) {
812                    return StringUtil.replace(
813                            fileName, CharPool.BACK_SLASH, CharPool.SLASH);
814            }
815    
816            @Override
817            public File[] sortFiles(File[] files) {
818                    if (files == null) {
819                            return null;
820                    }
821    
822                    Arrays.sort(files, new FileComparator());
823    
824                    List<File> directoryList = new ArrayList<File>();
825                    List<File> fileList = new ArrayList<File>();
826    
827                    for (int i = 0; i < files.length; i++) {
828                            if (files[i].isDirectory()) {
829                                    directoryList.add(files[i]);
830                            }
831                            else {
832                                    fileList.add(files[i]);
833                            }
834                    }
835    
836                    directoryList.addAll(fileList);
837    
838                    return directoryList.toArray(new File[directoryList.size()]);
839            }
840    
841            @Override
842            public String stripExtension(String fileName) {
843                    if (fileName == null) {
844                            return null;
845                    }
846    
847                    String ext = getExtension(fileName);
848    
849                    if (ext.length() > 0) {
850                            return fileName.substring(0, fileName.length() - ext.length() - 1);
851                    }
852                    else {
853                            return fileName;
854                    }
855            }
856    
857            @Override
858            public List<String> toList(Reader reader) {
859                    List<String> list = new ArrayList<String>();
860    
861                    try {
862                            UnsyncBufferedReader unsyncBufferedReader =
863                                    new UnsyncBufferedReader(reader);
864    
865                            String line = null;
866    
867                            while ((line = unsyncBufferedReader.readLine()) != null) {
868                                    list.add(line);
869                            }
870    
871                            unsyncBufferedReader.close();
872                    }
873                    catch (IOException ioe) {
874                    }
875    
876                    return list;
877            }
878    
879            @Override
880            public List<String> toList(String fileName) {
881                    try {
882                            return toList(new FileReader(fileName));
883                    }
884                    catch (IOException ioe) {
885                            return new ArrayList<String>();
886                    }
887            }
888    
889            @Override
890            public Properties toProperties(FileInputStream fis) {
891                    Properties properties = new Properties();
892    
893                    try {
894                            properties.load(fis);
895                    }
896                    catch (IOException ioe) {
897                    }
898    
899                    return properties;
900            }
901    
902            @Override
903            public Properties toProperties(String fileName) {
904                    try {
905                            return toProperties(new FileInputStream(fileName));
906                    }
907                    catch (IOException ioe) {
908                            return new Properties();
909                    }
910            }
911    
912            @Override
913            public void touch(File file) throws IOException {
914                    FileUtils.touch(file);
915            }
916    
917            @Override
918            public void touch(String fileName) throws IOException {
919                    touch(new File(fileName));
920            }
921    
922            @Override
923            public void unzip(File source, File destination) {
924                    ExpandTask.expand(source, destination);
925            }
926    
927            @Override
928            public void write(File file, byte[] bytes) throws IOException {
929                    write(file, bytes, 0, bytes.length, false);
930            }
931    
932            @Override
933            public void write(File file, byte[] bytes, boolean append)
934                    throws IOException {
935    
936                    write(file, bytes, 0, bytes.length, append);
937            }
938    
939            @Override
940            public void write(File file, byte[] bytes, int offset, int length)
941                    throws IOException {
942    
943                    write(file, bytes, offset, bytes.length, false);
944            }
945    
946            @Override
947            public void write(
948                            File file, byte[] bytes, int offset, int length, boolean append)
949                    throws IOException {
950    
951                    mkdirsParentFile(file);
952    
953                    FileOutputStream fileOutputStream = new FileOutputStream(file, append);
954    
955                    fileOutputStream.write(bytes, offset, length);
956    
957                    fileOutputStream.close();
958            }
959    
960            @Override
961            public void write(File file, InputStream is) throws IOException {
962                    mkdirsParentFile(file);
963    
964                    StreamUtil.transfer(is, new FileOutputStream(file));
965            }
966    
967            @Override
968            public void write(File file, String s) throws IOException {
969                    write(file, s, false);
970            }
971    
972            @Override
973            public void write(File file, String s, boolean lazy) throws IOException {
974                    write(file, s, lazy, false);
975            }
976    
977            @Override
978            public void write(File file, String s, boolean lazy, boolean append)
979                    throws IOException {
980    
981                    if (s == null) {
982                            return;
983                    }
984    
985                    mkdirsParentFile(file);
986    
987                    if (lazy && file.exists()) {
988                            String content = read(file);
989    
990                            if (content.equals(s)) {
991                                    return;
992                            }
993                    }
994    
995                    Writer writer = new OutputStreamWriter(
996                            new FileOutputStream(file, append), StringPool.UTF8);
997    
998                    writer.write(s);
999    
1000                    writer.close();
1001            }
1002    
1003            @Override
1004            public void write(String fileName, byte[] bytes) throws IOException {
1005                    write(new File(fileName), bytes);
1006            }
1007    
1008            @Override
1009            public void write(String fileName, InputStream is) throws IOException {
1010                    write(new File(fileName), is);
1011            }
1012    
1013            @Override
1014            public void write(String fileName, String s) throws IOException {
1015                    write(new File(fileName), s);
1016            }
1017    
1018            @Override
1019            public void write(String fileName, String s, boolean lazy)
1020                    throws IOException {
1021    
1022                    write(new File(fileName), s, lazy);
1023            }
1024    
1025            @Override
1026            public void write(String fileName, String s, boolean lazy, boolean append)
1027                    throws IOException {
1028    
1029                    write(new File(fileName), s, lazy, append);
1030            }
1031    
1032            @Override
1033            public void write(String pathName, String fileName, String s)
1034                    throws IOException {
1035    
1036                    write(new File(pathName, fileName), s);
1037            }
1038    
1039            @Override
1040            public void write(String pathName, String fileName, String s, boolean lazy)
1041                    throws IOException {
1042    
1043                    write(new File(pathName, fileName), s, lazy);
1044            }
1045    
1046            @Override
1047            public void write(
1048                            String pathName, String fileName, String s, boolean lazy,
1049                            boolean append)
1050                    throws IOException {
1051    
1052                    write(new File(pathName, fileName), s, lazy, append);
1053            }
1054    
1055            protected void mkdirsParentFile(File file) throws IOException {
1056                    File parentFile = file.getParentFile();
1057    
1058                    if (parentFile == null) {
1059                            return;
1060                    }
1061    
1062                    try {
1063                            mkdirs(parentFile);
1064                    }
1065                    catch (SecurityException se) {
1066    
1067                            // We may have the permission to write a specific file without
1068                            // having the permission to check if the parent file exists
1069    
1070                    }
1071            }
1072    
1073            private static final String[] _SAFE_FILE_NAME_1 = {
1074                    StringPool.AMPERSAND, StringPool.CLOSE_PARENTHESIS,
1075                    StringPool.OPEN_PARENTHESIS, StringPool.SEMICOLON
1076            };
1077    
1078            private static final String[] _SAFE_FILE_NAME_2 = {
1079                    "_AMP_", "_CP_", "_OP_", "_SEM_"
1080            };
1081    
1082            private static Log _log = LogFactoryUtil.getLog(FileImpl.class);
1083    
1084            private static FileImpl _instance = new FileImpl();
1085    
1086            private static class ExtractTextProcessCallable
1087                    implements ProcessCallable<String> {
1088    
1089                    public ExtractTextProcessCallable(byte[] data) {
1090                            _data = data;
1091                    }
1092    
1093                    @Override
1094                    public String call() throws ProcessException {
1095                            Tika tika = new Tika();
1096    
1097                            try {
1098                                    return tika.parseToString(
1099                                            new UnsyncByteArrayInputStream(_data));
1100                            }
1101                            catch (Exception e) {
1102                                    throw new ProcessException(e);
1103                            }
1104                    }
1105    
1106                    private static final long serialVersionUID = 1L;
1107    
1108                    private byte[] _data;
1109    
1110            }
1111    
1112    }