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