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