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