View Javadoc

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     LogLog.debug("Finalizing appender named ["+name+"].");
144     close();
145   }
146 
147 
148   /** 
149       Return the currently set {@link ErrorHandler} for this
150       Appender.  
151 
152       @since 0.9.0 */
153   public
154   ErrorHandler getErrorHandler() {
155     return this.errorHandler;
156   }
157 
158 
159   /**
160      Returns the head Filter.
161      
162      @since 1.1
163   */
164   public
165   Filter getFilter() {
166     return headFilter;
167   }
168 
169   /** 
170       Return the first filter in the filter chain for this
171       Appender. The return value may be <code>null</code> if no is
172       filter is set.
173       
174   */
175   public
176   final
177   Filter getFirstFilter() {
178     return headFilter;
179   }
180 
181   /**
182      Returns the layout of this appender. The value may be null.
183   */
184   public
185   Layout getLayout() {
186     return layout;
187   }
188 
189 
190   /**
191      Returns the name of this appender.
192      @return name, may be null.
193    */
194   public
195   final
196   String getName() {
197     return this.name;
198   }
199 
200   /**
201      Returns this appenders threshold level. See the {@link
202      #setThreshold} method for the meaning of this option.
203      
204      @since 1.1 */
205   public
206   Priority getThreshold() {
207     return threshold;
208   }
209 
210 
211   /**
212      Check whether the message level is below the appender's
213      threshold. If there is no threshold set, then the return value is
214      always <code>true</code>.
215 
216   */
217   public
218   boolean isAsSevereAsThreshold(Priority priority) {
219     return ((threshold == null) || priority.isGreaterOrEqual(threshold));
220   }
221 
222 
223   /**
224     * This method performs threshold checks and invokes filters before
225     * delegating actual logging to the subclasses specific {@link
226     * AppenderSkeleton#append} method.
227     * */
228   public
229   synchronized 
230   void doAppend(LoggingEvent event) {
231     if(closed) {
232       LogLog.error("Attempted to append to closed appender named ["+name+"].");
233       return;
234     }
235     
236     if(!isAsSevereAsThreshold(event.getLevel())) {
237       return;
238     }
239 
240     Filter f = this.headFilter;
241     
242     FILTER_LOOP:
243     while(f != null) {
244       switch(f.decide(event)) {
245       case Filter.DENY: return;
246       case Filter.ACCEPT: break FILTER_LOOP;
247       case Filter.NEUTRAL: f = f.getNext();
248       }
249     }
250     
251     this.append(event);    
252   }
253 
254   /** 
255       Set the {@link ErrorHandler} for this Appender.
256       @since 0.9.0
257   */
258   public
259   synchronized
260   void setErrorHandler(ErrorHandler eh) {
261     if(eh == null) {
262       // We do not throw exception here since the cause is probably a
263       // bad config file.
264       LogLog.warn("You have tried to set a null error-handler.");
265     } else {
266       this.errorHandler = eh;
267     }
268   }
269 
270   /**
271      Set the layout for this appender. Note that some appenders have
272      their own (fixed) layouts or do not use one. For example, the
273      {@link org.apache.log4j.net.SocketAppender} ignores the layout set
274      here. 
275   */
276   public
277   void setLayout(Layout layout) {
278     this.layout = layout;
279   }
280 
281   
282   /**
283      Set the name of this Appender.
284    */
285   public
286   void setName(String name) {
287     this.name = name;
288   }
289 
290 
291   /**
292      Set the threshold level. All log events with lower level
293      than the threshold level are ignored by the appender.
294      
295      <p>In configuration files this option is specified by setting the
296      value of the <b>Threshold</b> option to a level
297      string, such as "DEBUG", "INFO" and so on.
298      
299      @since 0.8.3 */
300   public
301   void setThreshold(Priority threshold) {
302     this.threshold = threshold;
303   }  
304 }