View Javadoc
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.time.Instant;
17  import java.util.Date;
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import ch.qos.logback.core.Context;
22  import ch.qos.logback.core.pattern.Converter;
23  import ch.qos.logback.core.pattern.ConverterUtil;
24  import ch.qos.logback.core.pattern.LiteralConverter;
25  import ch.qos.logback.core.pattern.parser.Node;
26  import ch.qos.logback.core.pattern.parser.Parser;
27  import ch.qos.logback.core.spi.ScanException;
28  import ch.qos.logback.core.pattern.util.AlmostAsIsEscapeUtil;
29  import ch.qos.logback.core.spi.ContextAwareBase;
30  
31  /**
32   * After parsing file name patterns, given a number or a date, instances of this
33   * class can be used to compute a file name according to the file name pattern
34   * and the current date or integer.
35   * 
36   * @author Ceki Gülcü
37   * 
38   */
39  public class FileNamePattern extends ContextAwareBase {
40  
41      static final Map<String, String> CONVERTER_MAP = new HashMap<String, String>();
42      static {
43          CONVERTER_MAP.put(IntegerTokenConverter.CONVERTER_KEY, IntegerTokenConverter.class.getName());
44          CONVERTER_MAP.put(DateTokenConverter.CONVERTER_KEY, DateTokenConverter.class.getName());
45      }
46  
47      String pattern;
48      Converter<Object> headTokenConverter;
49  
50      public FileNamePattern(String patternArg, Context contextArg) {
51          // the pattern is slashified
52          setPattern(FileFilterUtil.slashify(patternArg));
53          setContext(contextArg);
54          parse();
55          ConverterUtil.startConverters(this.headTokenConverter);
56      }
57  
58      void parse() {
59          try {
60              // http://jira.qos.ch/browse/LOGBACK-197
61              // we escape ')' for parsing purposes. Note that the original pattern is
62              // preserved
63              // because it is shown to the user in status messages. We don't want the escaped
64              // version
65              // to leak out.
66              String patternForParsing = escapeRightParantesis(pattern);
67              Parser<Object> p = new Parser<Object>(patternForParsing, new AlmostAsIsEscapeUtil());
68              p.setContext(context);
69              Node t = p.parse();
70              this.headTokenConverter = p.compile(t, CONVERTER_MAP);
71  
72          } catch (ScanException sce) {
73              addError("Failed to parse pattern \"" + pattern + "\".", sce);
74          }
75      }
76  
77      String escapeRightParantesis(String in) {
78          return pattern.replace(")", "\\)");
79      }
80  
81      public String toString() {
82          return pattern;
83      }
84  
85      @Override
86      public int hashCode() {
87          final int prime = 31;
88          int result = 1;
89          result = prime * result + ((pattern == null) ? 0 : pattern.hashCode());
90          return result;
91      }
92  
93      @Override
94      public boolean equals(Object obj) {
95          if (this == obj)
96              return true;
97          if (obj == null)
98              return false;
99          if (getClass() != obj.getClass())
100             return false;
101         FileNamePattern other = (FileNamePattern) obj;
102         if (pattern == null) {
103             if (other.pattern != null)
104                 return false;
105         } else if (!pattern.equals(other.pattern))
106             return false;
107         return true;
108     }
109 
110     public DateTokenConverter<Object> getPrimaryDateTokenConverter() {
111         Converter<Object> p = headTokenConverter;
112 
113         while (p != null) {
114             if (p instanceof DateTokenConverter) {
115                 DateTokenConverter<Object> dtc = (DateTokenConverter<Object>) p;
116                 // only primary converters should be returned as
117                 if (dtc.isPrimary())
118                     return dtc;
119             }
120 
121             p = p.getNext();
122         }
123 
124         return null;
125     }
126 
127     public IntegerTokenConverter getIntegerTokenConverter() {
128         Converter<Object> p = headTokenConverter;
129 
130         while (p != null) {
131             if (p instanceof IntegerTokenConverter) {
132                 return (IntegerTokenConverter) p;
133             }
134 
135             p = p.getNext();
136         }
137         return null;
138     }
139 
140     public boolean hasIntegerTokenCOnverter() {
141         IntegerTokenConverter itc = getIntegerTokenConverter();
142         return itc != null;
143     }
144 
145     public String convertMultipleArguments(Object... objectList) {
146         StringBuilder buf = new StringBuilder();
147         Converter<Object> c = headTokenConverter;
148         while (c != null) {
149             if (c instanceof MonoTypedConverter) {
150                 MonoTypedConverter monoTyped = (MonoTypedConverter) c;
151                 for (Object o : objectList) {
152                     if (monoTyped.isApplicable(o)) {
153                         buf.append(c.convert(o));
154                     }
155                 }
156             } else {
157                 buf.append(c.convert(objectList));
158             }
159             c = c.getNext();
160         }
161         return buf.toString();
162     }
163 
164     public String convert(Object o) {
165         StringBuilder buf = new StringBuilder();
166         Converter<Object> p = headTokenConverter;
167         while (p != null) {
168             buf.append(p.convert(o));
169             p = p.getNext();
170         }
171         return buf.toString();
172     }
173 
174     public String convertInt(int i) {
175         return convert(i);
176     }
177 
178     public void setPattern(String pattern) {
179         if (pattern != null) {
180             // Trailing spaces in the pattern are assumed to be undesired.
181             this.pattern = pattern.trim();
182         }
183     }
184 
185     public String getPattern() {
186         return pattern;
187     }
188 
189     /**
190      * Given date, convert this instance to a regular expression.
191      *
192      * Used to compute sub-regex when the pattern has both %d and %i, and the date
193      * is known.
194      * 
195      * @param date - known date
196      */
197     public String toRegexForFixedDate(Date date) {
198         StringBuilder buf = new StringBuilder();
199         Converter<Object> p = headTokenConverter;
200         while (p != null) {
201             if (p instanceof LiteralConverter) {
202                 buf.append(p.convert(null));
203             } else if (p instanceof IntegerTokenConverter) {
204                 buf.append("(\\d+)");
205             } else if (p instanceof DateTokenConverter) {
206                 buf.append(p.convert(date));
207             }
208             p = p.getNext();
209         }
210         return buf.toString();
211     }
212 
213 
214     /**
215      * Given date, convert this instance to a regular expression.
216      *
217      * Used to compute sub-regex when the pattern has both %d and %i, and the date
218      * is known.
219      *
220      * @param instant - known instant
221      */
222     public String toRegexForFixedDate(Instant instant) {
223         StringBuilder buf = new StringBuilder();
224         Converter<Object> p = headTokenConverter;
225         while (p != null) {
226             if (p instanceof LiteralConverter) {
227                 buf.append(p.convert(null));
228             } else if (p instanceof IntegerTokenConverter) {
229                 buf.append("(\\d+)");
230             } else if (p instanceof DateTokenConverter) {
231                 buf.append(p.convert(instant));
232             }
233             p = p.getNext();
234         }
235         return buf.toString();
236     }
237 
238 
239     /**
240      * Given date, convert this instance to a regular expression
241      */
242     public String toRegex() {
243         StringBuilder buf = new StringBuilder();
244         Converter<Object> p = headTokenConverter;
245         while (p != null) {
246             if (p instanceof LiteralConverter) {
247                 buf.append(p.convert(null));
248             } else if (p instanceof IntegerTokenConverter) {
249                 buf.append("\\d+");
250             } else if (p instanceof DateTokenConverter) {
251                 DateTokenConverter<Object> dtc = (DateTokenConverter<Object>) p;
252                 buf.append(dtc.toRegex());
253             }
254             p = p.getNext();
255         }
256         return buf.toString();
257     }
258 }