+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.helpers.AppenderAttachableImpl;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.OptionHandler;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * This appender forwards a logging request to another
+ * appender after possibly rewriting the logging event.
+ *
+ * This appender (with the appropriate policy)
+ * replaces the MapFilter, PropertyFilter and ReflectionFilter
+ * from log4j 1.3.
+ */
+public class RewriteAppender extends AppenderSkeleton
+ implements AppenderAttachable, UnrecognizedElementHandler {
+ /**
+ * Rewrite policy.
+ */
+ private RewritePolicy policy;
+ /**
+ * Nested appenders.
+ */
+ private final AppenderAttachableImpl appenders;
+
+ public RewriteAppender() {
+ appenders = new AppenderAttachableImpl();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void append(final LoggingEvent event) {
+ LoggingEvent rewritten = event;
+ if (policy != null) {
+ rewritten = policy.rewrite(event);
+ }
+ if (rewritten != null) {
+ synchronized (appenders) {
+ appenders.appendLoopOnAppenders(rewritten);
+ }
+ }
+ }
+
+ /**
+ * Add appender.
+ *
+ * @param newAppender appender to add, may not be null.
+ */
+ public void addAppender(final Appender newAppender) {
+ synchronized (appenders) {
+ appenders.addAppender(newAppender);
+ }
+ }
+
+ /**
+ * Get iterator over attached appenders.
+ * @return iterator or null if no attached appenders.
+ */
+ public Enumeration getAllAppenders() {
+ synchronized (appenders) {
+ return appenders.getAllAppenders();
+ }
+ }
+
+ /**
+ * Get appender by name.
+ *
+ * @param name name, may not be null.
+ * @return matching appender or null.
+ */
+ public Appender getAppender(final String name) {
+ synchronized (appenders) {
+ return appenders.getAppender(name);
+ }
+ }
+
+
+ /**
+ * Close this <code>AsyncAppender</code> by interrupting the dispatcher
+ * thread which will process all pending events before exiting.
+ */
+ public void close() {
+ closed = true;
+ //
+ // close all attached appenders.
+ //
+ synchronized (appenders) {
+ Enumeration iter = appenders.getAllAppenders();
+
+ if (iter != null) {
+ while (iter.hasMoreElements()) {
+ Object next = iter.nextElement();
+
+ if (next instanceof Appender) {
+ ((Appender) next).close();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Determines if specified appender is attached.
+ * @param appender appender.
+ * @return true if attached.
+ */
+ public boolean isAttached(final Appender appender) {
+ synchronized (appenders) {
+ return appenders.isAttached(appender);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ /**
+ * Removes and closes all attached appenders.
+ */
+ public void removeAllAppenders() {
+ synchronized (appenders) {
+ appenders.removeAllAppenders();
+ }
+ }
+
+ /**
+ * Removes an appender.
+ * @param appender appender to remove.
+ */
+ public void removeAppender(final Appender appender) {
+ synchronized (appenders) {
+ appenders.removeAppender(appender);
+ }
+ }
+
+ /**
+ * Remove appender by name.
+ * @param name name.
+ */
+ public void removeAppender(final String name) {
+ synchronized (appenders) {
+ appenders.removeAppender(name);
+ }
+ }
+
+
+ public void setRewritePolicy(final RewritePolicy rewritePolicy) {
+ policy = rewritePolicy;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public boolean parseUnrecognizedElement(final Element element,
+ final Properties props) throws Exception {
+ final String nodeName = element.getNodeName();
+ if ("rewritePolicy".equals(nodeName)) {
+ Object rewritePolicy =
+ org.apache.log4j.xml.DOMConfigurator.parseElement(
+ element, props, RewritePolicy.class);
+ if (rewritePolicy != null) {
+ if (rewritePolicy instanceof OptionHandler) {
+ ((OptionHandler) rewritePolicy).activateOptions();
+ }
+ this.setRewritePolicy((RewritePolicy) rewritePolicy);
+ }
+ return true;
+ }
+ return false;
+ }
+
+}