001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.log4j.rewrite;
018
019import org.apache.log4j.Appender;
020import org.apache.log4j.AppenderSkeleton;
021import org.apache.log4j.helpers.AppenderAttachableImpl;
022import org.apache.log4j.spi.AppenderAttachable;
023import org.apache.log4j.spi.LoggingEvent;
024import org.apache.log4j.spi.OptionHandler;
025import org.apache.log4j.xml.UnrecognizedElementHandler;
026import org.w3c.dom.Element;
027
028import java.util.Enumeration;
029import java.util.Properties;
030
031/**
032 * This appender forwards a logging request to another
033 * appender after possibly rewriting the logging event.
034 *
035 * This appender (with the appropriate policy)
036 * replaces the MapFilter, PropertyFilter and ReflectionFilter
037 * from log4j 1.3.
038 */
039public class RewriteAppender extends AppenderSkeleton
040     implements AppenderAttachable, UnrecognizedElementHandler {
041    /**
042     * Rewrite policy.
043     */
044    private RewritePolicy policy;
045    /**
046     * Nested appenders.
047     */
048    private final AppenderAttachableImpl appenders;
049
050    public RewriteAppender() {
051        appenders = new AppenderAttachableImpl();
052    }
053
054    /**
055     * {@inheritDoc}
056     */
057    protected void append(final LoggingEvent event) {
058        LoggingEvent rewritten = event;
059        if (policy != null) {
060            rewritten = policy.rewrite(event);
061        }
062        if (rewritten != null) {
063            synchronized (appenders) {
064              appenders.appendLoopOnAppenders(rewritten);
065            }
066        }
067    }
068
069    /**
070     * Add appender.
071     *
072     * @param newAppender appender to add, may not be null.
073     */
074    public void addAppender(final Appender newAppender) {
075      synchronized (appenders) {
076        appenders.addAppender(newAppender);
077      }
078    }
079
080    /**
081     * Get iterator over attached appenders.
082     * @return iterator or null if no attached appenders.
083     */
084    public Enumeration getAllAppenders() {
085      synchronized (appenders) {
086        return appenders.getAllAppenders();
087      }
088    }
089
090    /**
091     * Get appender by name.
092     *
093     * @param name name, may not be null.
094     * @return matching appender or null.
095     */
096    public Appender getAppender(final String name) {
097      synchronized (appenders) {
098        return appenders.getAppender(name);
099      }
100    }
101
102
103    /**
104     * Close this <code>AsyncAppender</code> by interrupting the dispatcher
105     * thread which will process all pending events before exiting.
106     */
107    public void close() {
108      closed = true;
109      //
110      //    close all attached appenders.
111      //
112      synchronized (appenders) {
113        Enumeration iter = appenders.getAllAppenders();
114
115        if (iter != null) {
116          while (iter.hasMoreElements()) {
117            Object next = iter.nextElement();
118
119            if (next instanceof Appender) {
120              ((Appender) next).close();
121            }
122          }
123        }
124      }
125    }
126
127    /**
128     * Determines if specified appender is attached.
129     * @param appender appender.
130     * @return true if attached.
131     */
132    public boolean isAttached(final Appender appender) {
133      synchronized (appenders) {
134        return appenders.isAttached(appender);
135      }
136    }
137
138    /**
139     * {@inheritDoc}
140     */
141    public boolean requiresLayout() {
142      return false;
143    }
144
145    /**
146     * Removes and closes all attached appenders.
147     */
148    public void removeAllAppenders() {
149      synchronized (appenders) {
150        appenders.removeAllAppenders();
151      }
152    }
153
154    /**
155     * Removes an appender.
156     * @param appender appender to remove.
157     */
158    public void removeAppender(final Appender appender) {
159      synchronized (appenders) {
160        appenders.removeAppender(appender);
161      }
162    }
163
164    /**
165     * Remove appender by name.
166     * @param name name.
167     */
168    public void removeAppender(final String name) {
169      synchronized (appenders) {
170        appenders.removeAppender(name);
171      }
172    }
173
174
175    public void setRewritePolicy(final RewritePolicy rewritePolicy) {
176        policy = rewritePolicy;
177    }
178    /**
179     * {@inheritDoc}
180     */
181    public boolean parseUnrecognizedElement(final Element element,
182                                            final Properties props) throws Exception {
183        final String nodeName = element.getNodeName();
184        if ("rewritePolicy".equals(nodeName)) {
185            Object rewritePolicy =
186                    org.apache.log4j.xml.DOMConfigurator.parseElement(
187                            element, props, RewritePolicy.class);
188            if (rewritePolicy != null) {
189                if (rewritePolicy instanceof OptionHandler) {
190                    ((OptionHandler) rewritePolicy).activateOptions();
191                }
192                this.setRewritePolicy((RewritePolicy) rewritePolicy);
193            }
194            return true;
195        }
196        return false;
197    }
198
199}