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;
15  
16  import static ch.qos.logback.core.CoreConstants.CODES_URL;
17  
18  import java.io.File;
19  import java.time.Instant;
20  import java.util.Locale;
21  import java.util.TimeZone;
22  import java.util.concurrent.atomic.AtomicLong;
23  
24  import ch.qos.logback.core.CoreConstants;
25  import ch.qos.logback.core.rolling.helper.ArchiveRemover;
26  import ch.qos.logback.core.rolling.helper.DateTokenConverter;
27  import ch.qos.logback.core.rolling.helper.RollingCalendar;
28  import ch.qos.logback.core.spi.ContextAwareBase;
29  
30  /**
31   * Base implementation of {@link TimeBasedFileNamingAndTriggeringPolicy}.
32   *
33   * <p>See also derived classes {@link DefaultTimeBasedFileNamingAndTriggeringPolicy} and
34   * {@link SizeAndTimeBasedFileNamingAndTriggeringPolicy}.
35   *
36   * </p>
37   *
38   * @param <E>
39   */
40  abstract public class TimeBasedFileNamingAndTriggeringPolicyBase<E> extends ContextAwareBase
41          implements TimeBasedFileNamingAndTriggeringPolicy<E> {
42  
43      static private String COLLIDING_DATE_FORMAT_URL = CODES_URL + "#rfa_collision_in_dateFormat";
44  
45      protected TimeBasedRollingPolicy<E> tbrp;
46  
47      protected ArchiveRemover archiveRemover = null;
48      protected String elapsedPeriodsFileName;
49      protected RollingCalendar rc;
50  
51      protected long artificialCurrentTime = -1;
52  
53      protected AtomicLong atomicNextCheck = new AtomicLong(0);
54      protected Instant dateInCurrentPeriod = null;
55  
56      protected boolean started = false;
57      protected boolean errorFree = true;
58  
59      public boolean isStarted() {
60          return started;
61      }
62  
63      public void start() {
64          DateTokenConverter<Object> dtc = tbrp.fileNamePattern.getPrimaryDateTokenConverter();
65          if (dtc == null) {
66              throw new IllegalStateException(
67                      "FileNamePattern [" + tbrp.fileNamePattern.getPattern() + "] does not contain a valid DateToken");
68          }
69  
70          if (dtc.getZoneId() != null) {
71              TimeZone tz = TimeZone.getTimeZone(dtc.getZoneId());
72              rc = new RollingCalendar(dtc.getDatePattern(), tz, Locale.getDefault());
73          } else {
74              rc = new RollingCalendar(dtc.getDatePattern());
75          }
76          addInfo("The date pattern is '" + dtc.getDatePattern() + "' from file name pattern '"
77                  + tbrp.fileNamePattern.getPattern() + "'.");
78          rc.printPeriodicity(this);
79  
80          if (!rc.isCollisionFree()) {
81              addError(
82                      "The date format in FileNamePattern will result in collisions in the names of archived log files.");
83              addError(CoreConstants.MORE_INFO_PREFIX + COLLIDING_DATE_FORMAT_URL);
84              withErrors();
85              return;
86          }
87  
88          long timestamp = getCurrentTime();
89          setDateInCurrentPeriod(timestamp);
90  
91          if (tbrp.getParentsRawFileProperty() != null) {
92              File currentFile = new File(tbrp.getParentsRawFileProperty());
93              if (currentFile.exists() && currentFile.canRead()) {
94                  timestamp = currentFile.lastModified();
95                  setDateInCurrentPeriod(timestamp);
96              }
97          }
98          addInfo("Setting initial period to " + dateInCurrentPeriod);
99          long nextCheck = computeNextCheck(timestamp);
100         atomicNextCheck.set(nextCheck);
101     }
102 
103     public void stop() {
104         started = false;
105     }
106 
107     protected long computeNextCheck(long timestamp) {
108         return rc.getNextTriggeringDate(Instant.ofEpochMilli(timestamp)).toEpochMilli();
109     }
110 
111     public String getElapsedPeriodsFileName() {
112         return elapsedPeriodsFileName;
113     }
114 
115     public String getCurrentPeriodsFileNameWithoutCompressionSuffix() {
116         return tbrp.fileNamePatternWithoutCompSuffix.convert(dateInCurrentPeriod);
117     }
118 
119     protected void setDateInCurrentPeriod(long timestamp) {
120         dateInCurrentPeriod = Instant.ofEpochMilli(timestamp);
121     }
122 
123     public void setCurrentTime(long timeInMillis) {
124         artificialCurrentTime = timeInMillis;
125     }
126 
127     public long getCurrentTime() {
128         // if time is forced return the time set by user
129         if (artificialCurrentTime >= 0) {
130             return artificialCurrentTime;
131         } else {
132             return System.currentTimeMillis();
133         }
134     }
135 
136     public void setTimeBasedRollingPolicy(TimeBasedRollingPolicy<E> _tbrp) {
137         this.tbrp = _tbrp;
138 
139     }
140 
141     public ArchiveRemover getArchiveRemover() {
142         return archiveRemover;
143     }
144 
145     protected void withErrors() {
146         errorFree = false;
147     }
148 
149     protected boolean isErrorFree() {
150         return errorFree;
151     }
152 
153 }