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