1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.rolling;
18
19 import org.apache.logging.log4j.core.pattern.ArrayPatternConverter;
20 import org.apache.logging.log4j.core.pattern.DatePatternConverter;
21 import org.apache.logging.log4j.core.pattern.FormattingInfo;
22 import org.apache.logging.log4j.core.pattern.PatternConverter;
23 import org.apache.logging.log4j.core.pattern.PatternParser;
24
25 import java.util.ArrayList;
26 import java.util.Calendar;
27 import java.util.Date;
28 import java.util.List;
29
30
31
32
33 public class PatternProcessor {
34
35 private static final String KEY = "FileConverter";
36
37 private static final char YEAR_CHAR = 'y';
38 private static final char MONTH_CHAR = 'M';
39 private static final char[] WEEK_CHARS = {'w', 'W'};
40 private static final char[] DAY_CHARS = {'D', 'd', 'F', 'E'};
41 private static final char[] HOUR_CHARS = {'H', 'K', 'h', 'k'};
42 private static final char MINUTE_CHAR = 'm';
43 private static final char SECOND_CHAR = 's';
44 private static final char MILLIS_CHAR = 'S';
45
46 private final ArrayPatternConverter[] patternConverters;
47 private final FormattingInfo[] patternFields;
48
49 private long prevFileTime = 0;
50 private long nextFileTime = 0;
51
52 private RolloverFrequency frequency = null;
53
54
55
56
57
58 public PatternProcessor(final String pattern) {
59 final PatternParser parser = createPatternParser();
60 final List<PatternConverter> converters = new ArrayList<PatternConverter>();
61 final List<FormattingInfo> fields = new ArrayList<FormattingInfo>();
62 parser.parse(pattern, converters, fields);
63 final FormattingInfo[] infoArray = new FormattingInfo[fields.size()];
64 patternFields = fields.toArray(infoArray);
65 final ArrayPatternConverter[] converterArray = new ArrayPatternConverter[converters.size()];
66 patternConverters = converters.toArray(converterArray);
67
68 for (final ArrayPatternConverter converter : patternConverters) {
69 if (converter instanceof DatePatternConverter) {
70 final DatePatternConverter dateConverter = (DatePatternConverter) converter;
71 frequency = calculateFrequency(dateConverter.getPattern());
72 }
73 }
74 }
75
76
77
78
79
80
81
82
83 public long getNextTime(final long current, final int increment, final boolean modulus) {
84 prevFileTime = nextFileTime;
85 long nextTime;
86
87 if (frequency == null) {
88 throw new IllegalStateException("Pattern does not contain a date");
89 }
90 final Calendar currentCal = Calendar.getInstance();
91 currentCal.setTimeInMillis(current);
92 final Calendar cal = Calendar.getInstance();
93 cal.set(currentCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
94 cal.set(Calendar.MILLISECOND, 0);
95 if (frequency == RolloverFrequency.ANNUALLY) {
96 increment(cal, Calendar.YEAR, increment, modulus);
97 nextTime = cal.getTimeInMillis();
98 cal.add(Calendar.YEAR, -1);
99 nextFileTime = cal.getTimeInMillis();
100 return nextTime;
101 }
102 if (frequency == RolloverFrequency.MONTHLY) {
103 increment(cal, Calendar.MONTH, increment, modulus);
104 nextTime = cal.getTimeInMillis();
105 cal.add(Calendar.MONTH, -1);
106 nextFileTime = cal.getTimeInMillis();
107 return nextTime;
108 }
109 if (frequency == RolloverFrequency.WEEKLY) {
110 increment(cal, Calendar.WEEK_OF_YEAR, increment, modulus);
111 nextTime = cal.getTimeInMillis();
112 cal.add(Calendar.WEEK_OF_YEAR, -1);
113 nextFileTime = cal.getTimeInMillis();
114 return nextTime;
115 }
116 cal.set(Calendar.DAY_OF_YEAR, currentCal.get(Calendar.DAY_OF_YEAR));
117 if (frequency == RolloverFrequency.DAILY) {
118 increment(cal, Calendar.DAY_OF_YEAR, increment, modulus);
119 nextTime = cal.getTimeInMillis();
120 cal.add(Calendar.DAY_OF_YEAR, -1);
121 nextFileTime = cal.getTimeInMillis();
122 return nextTime;
123 }
124 cal.set(Calendar.HOUR, currentCal.get(Calendar.HOUR));
125 if (frequency == RolloverFrequency.HOURLY) {
126 increment(cal, Calendar.HOUR, increment, modulus);
127 nextTime = cal.getTimeInMillis();
128 cal.add(Calendar.HOUR, -1);
129 nextFileTime = cal.getTimeInMillis();
130 return nextTime;
131 }
132 cal.set(Calendar.MINUTE, currentCal.get(Calendar.MINUTE));
133 if (frequency == RolloverFrequency.EVERY_MINUTE) {
134 increment(cal, Calendar.MINUTE, increment, modulus);
135 nextTime = cal.getTimeInMillis();
136 cal.add(Calendar.MINUTE, -1);
137 nextFileTime = cal.getTimeInMillis();
138 return nextTime;
139 }
140 cal.set(Calendar.SECOND, currentCal.get(Calendar.SECOND));
141 if (frequency == RolloverFrequency.EVERY_SECOND) {
142 increment(cal, Calendar.SECOND, increment, modulus);
143 nextTime = cal.getTimeInMillis();
144 cal.add(Calendar.SECOND, -1);
145 nextFileTime = cal.getTimeInMillis();
146 return nextTime;
147 }
148 increment(cal, Calendar.MILLISECOND, increment, modulus);
149 nextTime = cal.getTimeInMillis();
150 cal.add(Calendar.MILLISECOND, -1);
151 nextFileTime = cal.getTimeInMillis();
152 return nextTime;
153 }
154
155 private void increment(final Calendar cal, final int type, final int increment, final boolean modulate) {
156 final int interval = modulate ? increment - (cal.get(type) % increment) : increment;
157 cal.add(type, interval);
158 }
159
160
161
162
163
164
165 public final void formatFileName(final StringBuilder buf, final Object obj) {
166 final long time = prevFileTime == 0 ? System.currentTimeMillis() : prevFileTime;
167 formatFileName(buf, new Date(time), obj);
168 }
169
170
171
172
173
174
175 protected final void formatFileName(final StringBuilder buf, final Object... objects) {
176 for (int i = 0; i < patternConverters.length; i++) {
177 final int fieldStart = buf.length();
178 patternConverters[i].format(buf, objects);
179
180 if (patternFields[i] != null) {
181 patternFields[i].format(fieldStart, buf);
182 }
183 }
184 }
185
186 private RolloverFrequency calculateFrequency(final String pattern) {
187 if (patternContains(pattern, MILLIS_CHAR)) {
188 return RolloverFrequency.EVERY_MILLISECOND;
189 }
190 if (patternContains(pattern, SECOND_CHAR)) {
191 return RolloverFrequency.EVERY_SECOND;
192 }
193 if (patternContains(pattern, MINUTE_CHAR)) {
194 return RolloverFrequency.EVERY_MINUTE;
195 }
196 if (patternContains(pattern, HOUR_CHARS)) {
197 return RolloverFrequency.HOURLY;
198 }
199 if (patternContains(pattern, DAY_CHARS)) {
200 return RolloverFrequency.DAILY;
201 }
202 if (patternContains(pattern, WEEK_CHARS)) {
203 return RolloverFrequency.WEEKLY;
204 }
205 if (patternContains(pattern, MONTH_CHAR)) {
206 return RolloverFrequency.MONTHLY;
207 }
208 if (patternContains(pattern, YEAR_CHAR)) {
209 return RolloverFrequency.ANNUALLY;
210 }
211 return null;
212 }
213
214 private PatternParser createPatternParser() {
215
216 return new PatternParser(null, KEY, null);
217 }
218
219 private boolean patternContains(final String pattern, final char... chars) {
220 for (final char character : chars) {
221 if (patternContains(pattern, character)) {
222 return true;
223 }
224 }
225 return false;
226 }
227
228 private boolean patternContains(final String pattern, final char character) {
229 return pattern.indexOf(character) >= 0;
230 }
231 }