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