Source code: de/hunsicker/jalopy/plugin/AbstractAppender.java
1 /*
2 * Copyright (c) 2001-2002, Marco Hunsicker. All rights reserved.
3 *
4 * This software is distributable under the BSD license. See the terms of the
5 * BSD license in the documentation provided with this software.
6 */
7 package de.hunsicker.jalopy.plugin;
8
9 import de.hunsicker.util.ChainingRuntimeException;
10
11 import org.apache.log4j.AppenderSkeleton;
12 import org.apache.log4j.Level;
13 import org.apache.log4j.spi.LoggingEvent;
14
15 import org.apache.oro.text.regex.MalformedPatternException;
16 import org.apache.oro.text.regex.MatchResult;
17 import org.apache.oro.text.regex.Pattern;
18 import org.apache.oro.text.regex.PatternCompiler;
19 import org.apache.oro.text.regex.PatternMatcher;
20 import org.apache.oro.text.regex.Perl5Compiler;
21 import org.apache.oro.text.regex.Perl5Matcher;
22
23
24 /**
25 * Skeleton implementation of an appender which outputs messages in a visual component.
26 *
27 * @author <a href="http://jalopy.sf.net/contact.html">Marco Hunsicker</a>
28 * @version $Revision: 1.4 $
29 */
30 public abstract class AbstractAppender
31 extends AppenderSkeleton
32 implements SwingAppender
33 {
34 //~ Static variables/initializers ----------------------------------------------------
35
36 /** Position of the filename in the regex result. */
37 public static final int POS_FILENAME = 1;
38
39 /** Position of the lineno in the regex result. */
40 public static final int POS_LINE = 2;
41
42 /** Position of the message text in the regex result. */
43 public static final int POS_TEXT = 4;
44
45 /** Position of the message text in the regex result. */
46 public static final int POS_COLUMN = 3;
47
48 /** Name of the appender for output messages. */
49 private static final String APPENDER_NAME = "JalopyAppender" /* NOI18N */;
50
51 /**
52 * Regex to apply for Emacs-style messages. Messages must comply to the
53 * filename:line:column:text pattern.
54 */
55 private static final String PATTERN = "(.+?):(\\d+):(\\d+):\\s*(.+)" /* NOI18N */;
56
57 //~ Instance variables ---------------------------------------------------------------
58
59 /**
60 * The regex to parse the messages. If messages have a format similiar to Emacs
61 * messages (<code>filename:lineno:text</code>) the pattern will match.
62 */
63 protected final Pattern regex;
64
65 /** Matcher instance. */
66 private PatternMatcher _matcher;
67
68 //~ Constructors ---------------------------------------------------------------------
69
70 /**
71 * Creates a new AbstractAppender object.
72 *
73 * @throws ChainingRuntimeException DOCUMENT ME!
74 */
75 public AbstractAppender()
76 {
77 this.name = APPENDER_NAME;
78 this.layout = new SwingLayout();
79 setThreshold(Level.DEBUG);
80 _matcher = new Perl5Matcher();
81
82 PatternCompiler compiler = new Perl5Compiler();
83
84 try
85 {
86 this.regex = compiler.compile(PATTERN, Perl5Compiler.SINGLELINE_MASK);
87 }
88 catch (MalformedPatternException ex)
89 {
90 throw new ChainingRuntimeException(ex);
91 }
92 }
93
94 //~ Methods --------------------------------------------------------------------------
95
96 /**
97 * Does the actual outputting.
98 *
99 * @param ev logging event.
100 */
101 public abstract void append(LoggingEvent ev);
102
103
104 /**
105 * Sets the name of the appender. Overidden so that the initial name can't be
106 * changed.
107 *
108 * @param name appender name (ignored).
109 */
110 public final void setName(String name)
111 {
112 }
113
114
115 /**
116 * {@inheritDoc}
117 */
118 public void close()
119 {
120 }
121
122
123 /**
124 * {@inheritDoc}
125 */
126 public void done()
127 {
128 }
129
130
131 /**
132 * Parses the given message. To access the parsed information one may typically use:
133 * <pre class="snippet">
134 * MatchResult result = parseMessage(message);
135 * if (result == null)
136 * {
137 * // handle plain message
138 * ...
139 * }
140 * else
141 * {
142 * // this is an Emacs style message, you can easily access the
143 * // information
144 * String filename = result.group(POS_FILENAME);
145 * String line = result.group(POS_LINE);
146 * String column = result.group(POS_COLUMN);
147 * String text = result.group(POS_TEXT);
148 * ...
149 * }
150 * </pre>
151 *
152 * @param ev logging event.
153 *
154 * @return parsing result. Returns <code>null</code> if the message doesn't match the
155 * Emacs format <code>filename:line:column:text</code>.
156 */
157 public MatchResult parseMessage(LoggingEvent ev)
158 {
159 if (_matcher.matches(this.layout.format(ev), this.regex))
160 {
161 return _matcher.getMatch();
162 }
163
164 return null;
165 }
166
167
168 /**
169 * {@inheritDoc}
170 *
171 * @return always <code>true</code>.
172 */
173 public boolean requiresLayout()
174 {
175 return true;
176 }
177
178
179 /**
180 * {@inheritDoc}
181 *
182 * @return always <code>true</code>.
183 */
184 protected boolean checkEntryConditions()
185 {
186 return true;
187 }
188 }