1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, 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 v2.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;
15  
16  import ch.qos.logback.core.FileAppender;
17  import ch.qos.logback.core.rolling.helper.CompressionMode;
18  import ch.qos.logback.core.rolling.helper.FileNamePattern;
19  import ch.qos.logback.core.spi.ContextAwareBase;
20  
21  import static ch.qos.logback.core.util.Loader.isClassLoadable;
22  
23  /**
24   * Implements methods common to most, it not all, rolling policies. Currently
25   * such methods are limited to a compression mode getter/setter.
26   *
27   * @author Ceki Gülcü
28   */
29  public abstract class RollingPolicyBase extends ContextAwareBase implements RollingPolicy {
30      protected CompressionMode compressionMode = CompressionMode.NONE;
31  
32      FileNamePattern fileNamePattern;
33      // fileNamePatternStr is always slashified, see setter
34      protected String fileNamePatternStr;
35  
36      private FileAppender<?> parent;
37  
38      // use to name files within zip file, i.e. the zipEntry
39      FileNamePattern zipEntryFileNamePattern;
40      private boolean started;
41  
42      /**
43       * Given the FileNamePattern string, this method determines the compression mode
44       * depending on last letters of the fileNamePatternStr. Patterns ending with .gz
45       * imply GZIP compression, endings with '.zip' imply ZIP compression, endings with
46       * .xz imply XZ compression. Otherwise and by default, there is no compression.
47       *
48       */
49      protected void determineCompressionMode() {
50          if (fileNamePatternStr.endsWith(CompressionMode.GZ_SUFFIX)) {
51              addInfo("Will use gz compression");
52              compressionMode = CompressionMode.GZ;
53          } else if (fileNamePatternStr.endsWith(CompressionMode.ZIP_SUFFIX)) {
54              addInfo("Will use zip compression");
55              compressionMode = CompressionMode.ZIP;
56          } else if (fileNamePatternStr.endsWith(CompressionMode.XZ_SUFFIX)) {
57              addInfo("Will use xz compression");
58              compressionMode = CompressionMode.XZ;
59          } else {
60              addInfo("No compression will be used");
61              compressionMode = CompressionMode.NONE;
62          }
63      }
64  
65      /**
66       * If compression mode is XZ but the XZ library is missing, then fallback to GZ compression.
67       */
68      protected void adjustCompressionModeAndFileNamePatternStrIfNecessary() {
69          if (compressionMode == compressionMode.XZ) {
70              boolean xzLibraryLoadable = isClassLoadable("org.tukaani.xz.XZOutputStream", getContext());
71              if (!xzLibraryLoadable) {
72                  addWarn("XZ library missing, falling back to GZ compression");
73                  compressionMode = CompressionMode.GZ;
74                  fileNamePatternStr = replaceSuffix(fileNamePatternStr, CompressionMode.XZ_SUFFIX, CompressionMode.GZ_SUFFIX);
75              }
76          }
77      }
78  
79      private String replaceSuffix(String input, String existingSuffix, String newSuffix) {
80          int existingSuffixLen = existingSuffix.length();
81          if (input.endsWith(existingSuffix)) {
82              return input.substring(0, input.length() - existingSuffixLen) + newSuffix;
83          } else {
84              // unreachable code
85              throw new IllegalArgumentException("[" + input + "] should end with "+existingSuffix);
86          }
87      }
88  
89      public void setFileNamePattern(String fnp) {
90          fileNamePatternStr = fnp;
91      }
92  
93      public String getFileNamePattern() {
94          return fileNamePatternStr;
95      }
96  
97      public CompressionMode getCompressionMode() {
98          return compressionMode;
99      }
100 
101     public boolean isStarted() {
102         return started;
103     }
104 
105     public void start() {
106         started = true;
107     }
108 
109     public void stop() {
110         started = false;
111     }
112 
113     public void setParent(FileAppender<?> appender) {
114         this.parent = appender;
115     }
116 
117     public boolean isParentPrudent() {
118         return parent.isPrudent();
119     }
120 
121     public String getParentsRawFileProperty() {
122         return parent.rawFileProperty();
123     }
124 }