1 package net.logAnalyzer.patternParser;
2
3 import java.util.Vector;
4
5 import net.logAnalyzer.config.ConfigurationManager;
6 import net.logAnalyzer.converters.LAConverter;
7 import net.logAnalyzer.converters.NewLineConverter;
8
9 /***
10 * This class parses a log4j PatternLayout pattern.
11 * <p>
12 * The pattern could contain log4j basic converters, but also custom converters.
13 * </p>
14 * <p>
15 * Each pattern is declared in the <tt><logana:converters></tt> section
16 * of the configuration file loaded by
17 * {@link net.logAnalyzer.config.ConfigurationManager}.
18 * </p>
19 *
20 * @author Karim REFEYTON
21 * @version 0.1
22 */
23 public class PatternParser {
24 protected static final char CONVERTER_PREFIX = '%';
25
26 protected static final char OPENED_BRAKET = '{';
27
28 protected static final char CLOSED_BRAKET = '}';
29
30 private int linesToRead = 1;
31
32 /***
33 * Pattern to analyse.
34 */
35 private String pattern = null;
36
37 /***
38 * Default constructor.
39 *
40 * @param pattern
41 * Pattern to analysis.
42 */
43 public PatternParser(String pattern) {
44 this.pattern = pattern;
45 }
46
47 static final int STATE_LOOKING = 0;
48 static final int STATE_CONVERTER = 1;
49 static final int STATE_OPENBRAKET = 2;
50 static final int STATE_OPTION = 3;
51 /***
52 * Parses the pattern char by char. The pattern is transformed as a column
53 * list.
54 */
55 public LAConverter[] parse() throws PatternParsingException {
56
57 Vector converters = new Vector();
58
59 LAConverter converter = null;
60
61 StringBuffer buffer = new StringBuffer();
62
63 StringBuffer literal = new StringBuffer();
64
65 String letter = null;
66
67 StringBuffer option = new StringBuffer();
68
69 int state = STATE_LOOKING;
70
71 int patternLength = pattern.length();
72 for (int i = 0; i < patternLength; i++) {
73
74 char c = pattern.charAt(i);
75 switch (state) {
76 case STATE_LOOKING:
77
78 if (c == CONVERTER_PREFIX) {
79
80 buffer.append(c);
81
82 state = STATE_CONVERTER;
83 } else {
84
85 literal.append(c);
86 }
87 break;
88 case STATE_CONVERTER:
89
90 if (c == CONVERTER_PREFIX) {
91
92
93 literal.append(c);
94
95 buffer.setLength(0);
96 state = STATE_LOOKING;
97 } else {
98
99 letter = Character.toString(c);
100
101 buffer.append(c);
102
103 state = STATE_OPENBRAKET;
104 }
105 break;
106 case STATE_OPENBRAKET:
107
108 if (c == '{') {
109
110 buffer.append(c);
111
112 state = STATE_OPTION;
113 } else {
114 try {
115
116 converter = ConfigurationManager.getInstance()
117 .createConverter(letter);
118
119 addLiteral(converters, literal.toString());
120
121 addConverter(converters, converter);
122
123 i--;
124
125 letter = null;
126 literal.setLength(0);
127 buffer.setLength(0);
128 state = STATE_LOOKING;
129 } catch (PatternParsingException ppe) {
130
131
132 literal.append(buffer);
133 buffer.setLength(0);
134
135 i--;
136
137 state = STATE_LOOKING;
138 }
139 }
140 break;
141 case STATE_OPTION:
142
143 if (c == CLOSED_BRAKET) {
144 try {
145
146 converter = ConfigurationManager.getInstance()
147 .createConverter(letter, option.toString());
148
149 addLiteral(converters, literal.toString());
150
151 addConverter(converters, converter);
152
153 letter = null;
154 literal.setLength(0);
155 buffer.setLength(0);
156 option.setLength(0);
157 state = STATE_LOOKING;
158 } catch (PatternParsingException ppe) {
159
160
161 literal.append(buffer).append(CLOSED_BRAKET);
162
163 buffer.setLength(0);
164 option.setLength(0);
165 state = STATE_LOOKING;
166 }
167 } else if (c == CONVERTER_PREFIX && i < patternLength - 1
168 && pattern.charAt(i + 1) != CONVERTER_PREFIX) {
169
170
171 try {
172
173 converter = ConfigurationManager.getInstance()
174 .createConverter(letter);
175
176 addLiteral(converters, literal.toString());
177
178 addConverter(converters, converter);
179
180 i--;
181
182 letter = null;
183 literal.setLength(0);
184 literal.append(buffer);
185 buffer.setLength(0);
186 option.setLength(0);
187 state = STATE_LOOKING;
188 } catch (PatternParsingException ppe) {
189
190
191 literal.append(buffer);
192
193 i--;
194
195 buffer.setLength(0);
196 option.setLength(0);
197 state = STATE_LOOKING;
198 }
199 } else if (c == CONVERTER_PREFIX && i < patternLength - 1
200 && pattern.charAt(i + 1) == CONVERTER_PREFIX) {
201
202
203 literal.append(CONVERTER_PREFIX);
204
205 buffer.setLength(0);
206 option.setLength(0);
207 state = STATE_LOOKING;
208 } else {
209
210 option.append(c);
211 buffer.append(c);
212 }
213 break;
214 default:
215 }
216 }
217
218 addLiteral(converters, literal.toString());
219
220
221
222
223
224
225
226
227
228
229
230
231
232 LAConverter[] conv = new LAConverter[converters.size()];
233 return (LAConverter[]) converters.toArray(conv);
234 }
235
236 /***
237 * Constructs a converter from the converterChar parsed in the pattern.
238 *
239 * @param converters
240 * Converters.
241 * @param converter
242 * LAConverter to add in the converters list.
243 */
244 private void addConverter(Vector converters, LAConverter converter) {
245 if (converters.size() > 0) {
246 LAConverter previous = (LAConverter) converters.get(converters
247 .size() - 1);
248 previous.setNext(converter);
249 }
250 converters.add(converter);
251 if (converter instanceof NewLineConverter) {
252 linesToRead++;
253 }
254 }
255
256 /***
257 * Constructs a literal converter to handle the last parsed string.
258 *
259 * @param converters
260 * Converters.
261 * @param literal
262 * Literal parsed in the pattern.
263 * @throws PatternParsingException
264 * If can't create a literal converter.
265 */
266 private void addLiteral(Vector converters, String literal)
267 throws PatternParsingException {
268 if (literal != null && literal.length() > 0) {
269 LAConverter converter = ConfigurationManager.getInstance()
270 .createLiteralConverter(literal);
271 if (converters.size() > 0) {
272 LAConverter previous = (LAConverter) converters.get(converters
273 .size() - 1);
274 previous.setNext(converter);
275 }
276 converters.add(converter);
277 }
278 }
279
280 /***
281 * Returns the number of lines to read from the log file to parse a log
282 * messageLabel. For example, if a log4j pattern contains a %n converter inside
283 * (not at the end), the number of lines is 2.
284 *
285 * @return The number of line to read in a log file.
286 */
287 public int getLinesToRead() {
288 return linesToRead;
289 }
290 }