JAL-3026 srcjar files for VARNA and log4j
[jalview.git] / srcjar / org / apache / log4j / AppenderSkeleton.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.apache.log4j;
19
20 import org.apache.log4j.spi.Filter;
21 import org.apache.log4j.spi.ErrorHandler;
22 import org.apache.log4j.spi.OptionHandler;
23 import org.apache.log4j.spi.LoggingEvent;
24 import org.apache.log4j.helpers.OnlyOnceErrorHandler;
25 import org.apache.log4j.helpers.LogLog;
26
27
28 /** 
29  * Abstract superclass of the other appenders in the package.
30  *  
31  *  This class provides the code for common functionality, such as
32  *  support for threshold filtering and support for general filters.
33  *
34  * @since 0.8.1
35  * @author Ceki Gülcü 
36  * */
37 public abstract class AppenderSkeleton implements Appender, OptionHandler {
38
39   /** The layout variable does not need to be set if the appender
40       implementation has its own layout. */
41   protected Layout layout;
42
43   /** Appenders are named. */
44   protected String name;
45
46   /**
47      There is no level threshold filtering by default.  */
48   protected Priority threshold;
49
50   /** 
51       It is assumed and enforced that errorHandler is never null.
52   */
53   protected ErrorHandler errorHandler = new OnlyOnceErrorHandler();
54
55   /** The first filter in the filter chain. Set to <code>null</code>
56       initially. */
57   protected Filter headFilter;
58   /** The last filter in the filter chain. */
59   protected Filter tailFilter;
60
61   /**
62      Is this appender closed? 
63    */
64   protected boolean closed = false;
65
66     /**
67      * Create new instance.
68      */
69     public AppenderSkeleton() {
70         super();
71     }
72
73     /**
74      * Create new instance.
75      * Provided for compatibility with log4j 1.3.
76      *
77      * @param isActive true if appender is ready for use upon construction.
78      *                 Not used in log4j 1.2.x.
79      * @since 1.2.15
80      */
81     protected AppenderSkeleton(final boolean isActive) {
82         super();
83     }
84
85
86
87   /**
88      Derived appenders should override this method if option structure
89      requires it.  */
90   public
91   void activateOptions() {
92   }
93
94
95   /**
96      Add a filter to end of the filter list.
97
98      @since 0.9.0
99    */
100   public
101   void addFilter(Filter newFilter) {
102     if(headFilter == null) {
103       headFilter = tailFilter = newFilter;
104     } else {
105       tailFilter.setNext(newFilter);
106       tailFilter = newFilter;    
107     }
108   }
109
110   /**
111      Subclasses of <code>AppenderSkeleton</code> should implement this
112      method to perform actual logging. See also {@link #doAppend
113      AppenderSkeleton.doAppend} method.
114
115      @since 0.9.0
116   */
117   abstract
118   protected
119   void append(LoggingEvent event);
120
121
122   /**
123      Clear the filters chain.
124      
125      @since 0.9.0 */
126   public
127   void clearFilters() {
128     headFilter = tailFilter = null;
129   }
130
131   /**
132      Finalize this appender by calling the derived class'
133      <code>close</code> method.
134
135      @since 0.8.4 */
136   public
137   void finalize() {
138     // An appender might be closed then garbage collected. There is no
139     // point in closing twice.
140     if(this.closed) {
141         return;
142     }
143
144     LogLog.debug("Finalizing appender named ["+name+"].");
145     close();
146   }
147
148
149   /** 
150       Return the currently set {@link ErrorHandler} for this
151       Appender.  
152
153       @since 0.9.0 */
154   public
155   ErrorHandler getErrorHandler() {
156     return this.errorHandler;
157   }
158
159
160   /**
161      Returns the head Filter.
162      
163      @since 1.1
164   */
165   public
166   Filter getFilter() {
167     return headFilter;
168   }
169
170   /** 
171       Return the first filter in the filter chain for this
172       Appender. The return value may be <code>null</code> if no is
173       filter is set.
174       
175   */
176   public
177   final
178   Filter getFirstFilter() {
179     return headFilter;
180   }
181
182   /**
183      Returns the layout of this appender. The value may be null.
184   */
185   public
186   Layout getLayout() {
187     return layout;
188   }
189
190
191   /**
192      Returns the name of this appender.
193      @return name, may be null.
194    */
195   public
196   final
197   String getName() {
198     return this.name;
199   }
200
201   /**
202      Returns this appenders threshold level. See the {@link
203      #setThreshold} method for the meaning of this option.
204      
205      @since 1.1 */
206   public
207   Priority getThreshold() {
208     return threshold;
209   }
210
211
212   /**
213      Check whether the message level is below the appender's
214      threshold. If there is no threshold set, then the return value is
215      always <code>true</code>.
216
217   */
218   public
219   boolean isAsSevereAsThreshold(Priority priority) {
220     return ((threshold == null) || priority.isGreaterOrEqual(threshold));
221   }
222
223
224   /**
225     * This method performs threshold checks and invokes filters before
226     * delegating actual logging to the subclasses specific {@link
227     * AppenderSkeleton#append} method.
228     * */
229   public
230   synchronized 
231   void doAppend(LoggingEvent event) {
232     if(closed) {
233       LogLog.error("Attempted to append to closed appender named ["+name+"].");
234       return;
235     }
236     
237     if(!isAsSevereAsThreshold(event.getLevel())) {
238       return;
239     }
240
241     Filter f = this.headFilter;
242     
243     FILTER_LOOP:
244     while(f != null) {
245       switch(f.decide(event)) {
246       case Filter.DENY: return;
247       case Filter.ACCEPT: break FILTER_LOOP;
248       case Filter.NEUTRAL: f = f.getNext();
249       }
250     }
251     
252     this.append(event);    
253   }
254
255   /** 
256       Set the {@link ErrorHandler} for this Appender.
257       @since 0.9.0
258   */
259   public
260   synchronized
261   void setErrorHandler(ErrorHandler eh) {
262     if(eh == null) {
263       // We do not throw exception here since the cause is probably a
264       // bad config file.
265       LogLog.warn("You have tried to set a null error-handler.");
266     } else {
267       this.errorHandler = eh;
268     }
269   }
270
271   /**
272      Set the layout for this appender. Note that some appenders have
273      their own (fixed) layouts or do not use one. For example, the
274      {@link org.apache.log4j.net.SocketAppender} ignores the layout set
275      here. 
276   */
277   public
278   void setLayout(Layout layout) {
279     this.layout = layout;
280   }
281
282   
283   /**
284      Set the name of this Appender.
285    */
286   public
287   void setName(String name) {
288     this.name = name;
289   }
290
291
292   /**
293      Set the threshold level. All log events with lower level
294      than the threshold level are ignored by the appender.
295      
296      <p>In configuration files this option is specified by setting the
297      value of the <b>Threshold</b> option to a level
298      string, such as "DEBUG", "INFO" and so on.
299      
300      @since 0.8.3 */
301   public
302   void setThreshold(Priority threshold) {
303     this.threshold = threshold;
304   }  
305 }