1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.rolling.helper;
15  
16  import java.util.concurrent.ExecutorService;
17  import java.util.concurrent.Future;
18  
19  import ch.qos.logback.core.rolling.RolloverFailure;
20  import ch.qos.logback.core.spi.ContextAwareBase;
21  import ch.qos.logback.core.util.DynamicClassLoadingException;
22  import ch.qos.logback.core.util.IncompatibleClassException;
23  
24  import static ch.qos.logback.core.util.OptionHelper.instantiateByClassName;
25  
26  /**
27   * The <code>Compression</code> class implements ZIP and GZ file
28   * compression/decompression methods.
29   *
30   * @author Ceki G&uuml;lc&uuml;
31   */
32  public class Compressor extends ContextAwareBase {
33  
34      public static final String COULD_NOT_OBTAIN_COMPRESSION_STRATEGY_MESSAGE = "Could not obtain compression strategy";
35      public static final String XZ_COMPRESSION_STRATEGY_CLASS_NAME = "ch.qos.logback.core.rolling.helper.XZCompressionStrategy";
36  
37      final CompressionMode compressionMode;
38  
39      static final int BUFFER_SIZE = 8192;
40  
41      public Compressor(CompressionMode compressionMode) {
42          this.compressionMode = compressionMode;
43      }
44  
45      /**
46       * @param originalFileName
47       * @param compressedFileName
48       * @param innerEntryName       The name of the file within the zip file. Use for
49       *                             ZIP compression.
50       */
51      public void compress(String originalFileName, String compressedFileName, String innerEntryName) {
52          CompressionStrategy compressionStrategy = makeCompressionStrategy(compressionMode);
53          if (compressionStrategy == null) {
54              addWarn(COULD_NOT_OBTAIN_COMPRESSION_STRATEGY_MESSAGE);
55              return;
56          }
57          compressionStrategy.setContext(getContext());
58          compressionStrategy.compress(originalFileName, compressedFileName, innerEntryName);
59      }
60  
61      CompressionStrategy makeCompressionStrategy(CompressionMode compressionMode) {
62          switch (compressionMode) {
63          case GZ:
64              return new GZCompressionStrategy();
65          case ZIP:
66              return new ZipCompressionStrategy();
67          case XZ:
68              return dynamicInstantiation(XZ_COMPRESSION_STRATEGY_CLASS_NAME);
69          case NONE:
70              throw new UnsupportedOperationException("compress method called in NONE compression mode");
71          default:
72              return null;
73          }
74      }
75  
76      private CompressionStrategy dynamicInstantiation(String className) {
77          try {
78              return (CompressionStrategy) instantiateByClassName(className, CompressionStrategy.class, getContext());
79          } catch (IncompatibleClassException | DynamicClassLoadingException e) {
80              addError("Could not instantiate " + className, e);
81              return null;
82          }
83      }
84  
85      static public String computeFileNameStrWithoutCompSuffix(String fileNamePatternStr, CompressionMode compressionMode) {
86          int len = fileNamePatternStr.length();
87          switch (compressionMode) {
88          case GZ:
89              if (fileNamePatternStr.endsWith(".gz"))
90                  return fileNamePatternStr.substring(0, len - 3);
91              else
92                  return fileNamePatternStr;
93          case ZIP:
94              if (fileNamePatternStr.endsWith(".zip"))
95                  return fileNamePatternStr.substring(0, len - 4);
96              else
97                  return fileNamePatternStr;
98          case XZ:
99              if (fileNamePatternStr.endsWith(".xz"))
100                 return fileNamePatternStr.substring(0, len - 3);
101             else
102                 return fileNamePatternStr;
103         case NONE:
104             return fileNamePatternStr;
105         }
106         throw new IllegalStateException("Execution should not reach this point");
107     }
108 
109     @Override
110     public String toString() {
111         return this.getClass().getName();
112     }
113 
114     public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure {
115         CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
116         ExecutorService executorService = context.getExecutorService();
117         Future<?> future = executorService.submit(runnable);
118         return future;
119     }
120 
121     class CompressionRunnable implements Runnable {
122         final String nameOfFile2Compress;
123         final String nameOfCompressedFile;
124         final String innerEntryName;
125 
126         public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) {
127             this.nameOfFile2Compress = nameOfFile2Compress;
128             this.nameOfCompressedFile = nameOfCompressedFile;
129             this.innerEntryName = innerEntryName;
130         }
131 
132         public void run() {
133 
134             Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
135         }
136     }
137 
138 }