View Javadoc

1   /**
2    * LOGBack: the reliable, fast and flexible logging library for Java.
3    * 
4    * Copyright (C) 1999-2006, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  
11  package ch.qos.logback.core.rolling.helper;
12  
13  import java.text.SimpleDateFormat;
14  import java.util.Calendar;
15  import java.util.Date;
16  import java.util.GregorianCalendar;
17  import java.util.Locale;
18  import java.util.TimeZone;
19  
20  import ch.qos.logback.core.spi.ContextAwareBase;
21  
22  /**
23   * RollingCalendar is a helper class to
24   * {@link ch.qos.logback.core.rolling.TimeBasedRollingPolicy } or similar
25   * timed-based rolling policies. Given a periodicity type and the current time,
26   * it computes the start of the next interval (i.e. the triggering date).
27   * 
28   * @author Ceki Gülcü
29   * 
30   */
31  public class RollingCalendar extends GregorianCalendar {
32  
33    private static final long serialVersionUID = -5937537740925066161L;
34  
35    // The gmtTimeZone is used only in computeCheckPeriod() method.
36    static final TimeZone GMT_TIMEZONE = TimeZone.getTimeZone("GMT");
37  
38    PeriodicityType type = PeriodicityType.ERRONEOUS;
39  
40    public RollingCalendar() {
41      super();
42    }
43  
44    public RollingCalendar(TimeZone tz, Locale locale) {
45      super(tz, locale);
46    }
47  
48    public void init(String datePattern) {
49      type = computePeriodicity(datePattern);
50    }
51  
52    private void setType(PeriodicityType type) {
53      this.type = type;
54    }
55  
56    public long getNextTriggeringMillis(Date now) {
57      return getNextTriggeringDate(now).getTime();
58    }
59  
60    // This method computes the roll over period by looping over the
61    // periods, starting with the shortest, and stopping when the r0 is
62    // different from from r1, where r0 is the epoch formatted according
63    // the datePattern (supplied by the user) and r1 is the
64    // epoch+nextMillis(i) formatted according to datePattern. All date
65    // formatting is done in GMT and not local format because the test
66    // logic is based on comparisons relative to 1970-01-01 00:00:00
67    // GMT (the epoch).
68    public PeriodicityType computePeriodicity(String datePattern) {
69      RollingCalendar rollingCalendar = new RollingCalendar(GMT_TIMEZONE, Locale
70          .getDefault());
71  
72      // set sate to 1970-01-01 00:00:00 GMT
73      Date epoch = new Date(0);
74  
75      if (datePattern != null) {
76        for (PeriodicityType i : PeriodicityType.VALID_ORDERED_LIST) {
77          SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
78          simpleDateFormat.setTimeZone(GMT_TIMEZONE); // all date formatting done in GMT
79  
80          String r0 = simpleDateFormat.format(epoch);
81          rollingCalendar.setType(i);
82  
83          Date next = new Date(rollingCalendar.getNextTriggeringMillis(epoch));
84          String r1 = simpleDateFormat.format(next);
85  
86          // System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
87          if ((r0 != null) && (r1 != null) && !r0.equals(r1)) {
88            return i;
89          }
90        }
91      }
92      // we failed
93      return PeriodicityType.ERRONEOUS; 
94    }
95  
96    public void printPeriodicity(ContextAwareBase cab) {
97      switch (type) {
98      case TOP_OF_SECOND:
99        cab.addInfo("Roll-over every second.");
100 
101       break;
102 
103     case TOP_OF_MINUTE:
104       cab.addInfo("Roll-over every minute.");
105 
106       break;
107 
108     case TOP_OF_HOUR:
109       cab.addInfo("Roll-over at the top of every hour.");
110 
111       break;
112 
113     case HALF_DAY:
114       cab.addInfo("Roll-over at midday and midnight.");
115 
116       break;
117 
118     case TOP_OF_DAY:
119       cab.addInfo("Roll-over at midnight.");
120 
121       break;
122 
123     case TOP_OF_WEEK:
124       cab.addInfo("Rollover at the start of week.");
125 
126       break;
127 
128     case TOP_OF_MONTH:
129       cab.addInfo("Rollover at start of every month.");
130 
131       break;
132 
133     default:
134       cab.addInfo("Unknown periodicity.");
135     }
136   }
137 
138   public Date getRelativeDate(Date now, int periods) {
139     this.setTime(now);
140 
141     switch (type) {
142     case TOP_OF_SECOND:
143       this.set(Calendar.MILLISECOND, 0);
144       this.add(Calendar.SECOND, periods);
145 
146       break;
147 
148     case TOP_OF_MINUTE:
149       this.set(Calendar.SECOND, 0);
150       this.set(Calendar.MILLISECOND, 0);
151       this.add(Calendar.MINUTE, periods);
152 
153       break;
154 
155     case TOP_OF_HOUR:
156       this.set(Calendar.MINUTE, 0);
157       this.set(Calendar.SECOND, 0);
158       this.set(Calendar.MILLISECOND, 0);
159       this.add(Calendar.HOUR_OF_DAY, periods);
160 
161       break;
162 
163     case TOP_OF_DAY:
164       this.set(Calendar.HOUR_OF_DAY, 0);
165       this.set(Calendar.MINUTE, 0);
166       this.set(Calendar.SECOND, 0);
167       this.set(Calendar.MILLISECOND, 0);
168       this.add(Calendar.DATE, periods);
169 
170       break;
171 
172     case TOP_OF_WEEK:
173       this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
174       this.set(Calendar.HOUR_OF_DAY, 0);
175       this.set(Calendar.MINUTE, 0);
176       this.set(Calendar.SECOND, 0);
177       this.set(Calendar.MILLISECOND, 0);
178       this.add(Calendar.WEEK_OF_YEAR, periods);
179 
180       break;
181 
182     case TOP_OF_MONTH:
183       this.set(Calendar.DATE, 1);
184       this.set(Calendar.HOUR_OF_DAY, 0);
185       this.set(Calendar.MINUTE, 0);
186       this.set(Calendar.SECOND, 0);
187       this.set(Calendar.MILLISECOND, 0);
188       this.add(Calendar.MONTH, periods);
189 
190       break;
191 
192     default:
193       throw new IllegalStateException("Unknown periodicity type.");
194     }
195 
196     return getTime();
197   }
198   
199   public Date getNextTriggeringDate(Date now) {
200     return getRelativeDate(now, 1);
201   }
202 }