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