logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sde...@apache.org
Subject svn commit: r1178304 [4/6] - in /logging/chainsaw/trunk: ./ src/main/java/org/apache/log4j/ src/main/java/org/apache/log4j/db/ src/main/java/org/apache/log4j/db/dialect/ src/main/java/org/apache/log4j/helpers/ src/main/java/org/apache/log4j/net/ src/ma...
Date Mon, 03 Oct 2011 06:15:43 GMT
Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginRegistry.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginRegistry.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginRegistry.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,303 @@
+/*
+ * 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.plugins;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.spi.LoggerRepositoryEventListener;
+
+
+/**
+ * This is a registry for Plugin instances. It provides methods to
+ * start and stop plugin objects individually and to stop all
+ * plugins for a repository.
+ *
+ * @author Mark Womack
+ * @author Paul Smith
+ */
+public final class PluginRegistry {
+    /**
+     * The pluginMap is keyed by plugin name and contains plugins as values.
+     * key=plugin.getName, value=plugin
+     */
+    private final Map pluginMap;
+    /**
+     * Logger repository.
+     */
+    private final LoggerRepositoryEx loggerRepository;
+
+    /**
+     * the listener used to listen for repository events.
+     */
+    private final RepositoryListener listener = new RepositoryListener();
+    /**
+     * List of listeners.
+     */
+    private final List listenerList =
+            Collections.synchronizedList(new ArrayList());
+
+    /**
+     * Creates a new instance.
+     * @param repository logger repository.
+     */
+    public PluginRegistry(final LoggerRepositoryEx repository) {
+        super();
+        pluginMap = new HashMap();
+        this.loggerRepository = repository;
+        this.loggerRepository.addLoggerRepositoryEventListener(listener);
+    }
+
+    /**
+     * Get logger repository.
+     * @return logger repository.
+     */
+    public LoggerRepositoryEx getLoggerRepository() {
+        return loggerRepository;
+    }
+
+
+    /**
+     * Returns true if the specified name is already taken by
+     * an existing Plugin registered within the scope of the specified
+     * LoggerRepository.
+     *
+     * @param name The name to check the repository for
+     * @return true if the name is already in use, otherwise false
+     */
+    public boolean pluginNameExists(final String name) {
+        synchronized (pluginMap) {
+            return pluginMap.containsKey(name);
+        }
+    }
+
+
+    /**
+     * Adds a plugin to the plugin registry.
+     * If a plugin with the same name exists
+     * already, it is shutdown and removed.
+     *
+     * @param plugin the plugin to add.
+     */
+    public void addPlugin(final Plugin plugin) {
+        // put plugin into the repository's reciever map
+        synchronized (pluginMap) {
+            String name = plugin.getName();
+
+            // make sure the plugin has reference to repository
+            plugin.setLoggerRepository(getLoggerRepository());
+
+            Plugin existingPlugin = (Plugin) pluginMap.get(name);
+            if (existingPlugin != null) {
+                existingPlugin.shutdown();
+            }
+
+            // put the new plugin into the map
+            pluginMap.put(name, plugin);
+            firePluginStarted(plugin);
+        }
+    }
+
+
+    /**
+     * Calls the pluginStarted method on every registered PluginListener.
+     *
+     * @param plugin The plugin that has been started.
+     */
+    private void firePluginStarted(final Plugin plugin) {
+        PluginEvent e = null;
+        synchronized (listenerList) {
+            for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+                PluginListener l = (PluginListener) iter.next();
+                if (e == null) {
+                    e = new PluginEvent(plugin);
+                }
+                l.pluginStarted(e);
+            }
+        }
+    }
+
+
+    /**
+     * Calls the pluginStopped method for every registered PluginListner.
+     *
+     * @param plugin The plugin that has been stopped.
+     */
+    private void firePluginStopped(final Plugin plugin) {
+        PluginEvent e = null;
+        synchronized (listenerList) {
+            for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+                PluginListener l = (PluginListener) iter.next();
+                if (e == null) {
+                    e = new PluginEvent(plugin);
+                }
+                l.pluginStopped(e);
+            }
+        }
+    }
+
+
+    /**
+     * Returns all the plugins for a given repository.
+     *
+     * @return List list of plugins from the repository.
+     */
+    public List getPlugins() {
+        synchronized (pluginMap) {
+            List pluginList = new ArrayList(pluginMap.size());
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                pluginList.add(iter.next());
+            }
+            return pluginList;
+        }
+    }
+
+
+    /**
+     * Returns all the plugins for a given repository that are instances
+     * of a certain class.
+     *
+     * @param pluginClass the class the plugin must implement to be selected.
+     * @return List list of plugins from the repository.
+     */
+    public List getPlugins(final Class pluginClass) {
+        synchronized (pluginMap) {
+            List pluginList = new ArrayList(pluginMap.size());
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                Object plugin = iter.next();
+
+                if (pluginClass.isInstance(plugin)) {
+                    pluginList.add(plugin);
+                }
+            }
+            return pluginList;
+        }
+    }
+
+
+    /**
+     * Stops a plugin by plugin name and repository.
+     *
+     * @param pluginName the name of the plugin to stop.
+     * @return Plugin the plugin, if stopped, or null if the
+     *         the plugin was not found in the registry.
+     */
+    public Plugin stopPlugin(final String pluginName) {
+        synchronized (pluginMap) {
+            Plugin plugin = (Plugin) pluginMap.get(pluginName);
+
+            if (plugin == null) {
+                return null;
+            }
+
+            // shutdown the plugin
+            plugin.shutdown();
+
+            // remove it from the plugin map
+            pluginMap.remove(pluginName);
+            firePluginStopped(plugin);
+
+            // return it for future use
+            return plugin;
+        }
+    }
+
+    /**
+     * Stops all plugins in the given logger repository.
+     */
+    public void stopAllPlugins() {
+        synchronized (pluginMap) {
+            // remove the listener for this repository
+            loggerRepository.removeLoggerRepositoryEventListener(listener);
+
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                Plugin plugin = (Plugin) iter.next();
+                plugin.shutdown();
+                firePluginStopped(plugin);
+            }
+        }
+    }
+
+
+    /**
+     * Adds a PluginListener to this registry to be notified
+     * of PluginEvents.
+     *
+     * @param l PluginListener to add to this registry
+     */
+    public void addPluginListener(final PluginListener l) {
+        listenerList.add(l);
+    }
+
+
+    /**
+     * Removes a particular PluginListener from this registry
+     * such that it will no longer be notified of PluginEvents.
+     *
+     * @param l PluginListener to remove
+     */
+    public void removePluginListener(final PluginListener l) {
+        listenerList.remove(l);
+    }
+
+    /**
+     * Internal class used to handle listener events from repositories.
+     */
+    private class RepositoryListener implements LoggerRepositoryEventListener {
+        /**
+         * Stops all plugins associated with the repository being reset.
+         *
+         * @param repository the repository that was reset.
+         */
+        public void configurationResetEvent(final LoggerRepository repository) {
+            PluginRegistry.this.stopAllPlugins();
+        }
+
+
+        /**
+         * Called when the repository configuration is changed.
+         *
+         * @param repository the repository that was changed.
+         */
+        public void configurationChangedEvent(
+                final LoggerRepository repository) {
+            // do nothing with this event
+        }
+
+
+        /**
+         * Stops all plugins associated with the repository being shutdown.
+         *
+         * @param repository the repository being shutdown.
+         */
+        public void shutdownEvent(final LoggerRepository repository) {
+            PluginRegistry.this.stopAllPlugins();
+        }
+    }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,222 @@
+/*
+ * 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.plugins;
+
+import org.apache.log4j.spi.ComponentBase;
+import org.apache.log4j.spi.LoggerRepository;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+
+/**
+ * A convienent abstract class for plugin subclasses that implements
+ * the basic methods of the Plugin interface. Subclasses are required
+ * to implement the isActive(), activateOptions(), and shutdown()
+ * methods.
+ * <p/>
+ * <p>Developers are not required to subclass PluginSkeleton to
+ * develop their own plugins (they are only required to implement the
+ * Plugin interface), but it provides a convenient base class to start
+ * from.
+ * <p/>
+ * Contributors: Nicko Cadell
+ *
+ * @author Mark Womack (mwomack@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ */
+public abstract class PluginSkeleton extends ComponentBase implements Plugin {
+    /**
+     * Name of this plugin.
+     */
+    protected String name = "plugin";
+
+    /**
+     * Active state of plugin.
+     */
+    protected boolean active;
+
+    /**
+     * This is a delegate that does all the PropertyChangeListener
+     * support.
+     */
+    private PropertyChangeSupport propertySupport =
+            new PropertyChangeSupport(this);
+
+    /**
+     * Construct new instance.
+     */
+    protected PluginSkeleton() {
+        super();
+    }
+
+    /**
+     * Gets the name of the plugin.
+     *
+     * @return String the name of the plugin.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the name of the plugin and notifies
+     * PropertyChangeListeners of the change.
+     *
+     * @param newName the name of the plugin to set.
+     */
+    public void setName(final String newName) {
+        String oldName = this.name;
+        this.name = newName;
+        propertySupport.firePropertyChange("name", oldName, this.name);
+    }
+
+    /**
+     * Gets the logger repository for this plugin.
+     *
+     * @return LoggerRepository the logger repository this plugin will affect.
+     */
+    public LoggerRepository getLoggerRepository() {
+        return repository;
+    }
+
+    /**
+     * Sets the logger repository used by this plugin and notifies a
+     * relevant PropertyChangeListeners registered. This
+     * repository will be used by the plugin functionality.
+     *
+     * @param repository the logger repository that this plugin should affect.
+     */
+    public void setLoggerRepository(final LoggerRepository repository) {
+        Object oldValue = this.repository;
+        this.repository = repository;
+        firePropertyChange("loggerRepository", oldValue, this.repository);
+    }
+
+    /**
+     * Returns whether this plugin is Active or not.
+     *
+     * @return true/false
+     */
+    public synchronized boolean isActive() {
+        return active;
+    }
+
+    /**
+     * Returns true if the plugin has the same name and logger repository as the
+     * testPlugin passed in.
+     *
+     * @param testPlugin The plugin to test equivalency against.
+     * @return Returns true if testPlugin is considered to be equivalent.
+     */
+    public boolean isEquivalent(final Plugin testPlugin) {
+        return (repository == testPlugin.getLoggerRepository())
+                && ((this.name == null && testPlugin.getName() == null)
+                || (this.name != null
+                           && name.equals(testPlugin.getName())))
+                && this.getClass().equals(testPlugin.getClass());
+    }
+
+    /**
+     * Add property change listener.
+     * @param listener listener.
+     */
+    public final void addPropertyChangeListener(
+            final PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Add property change listener for one property only.
+     * @param propertyName property name.
+     * @param listener listener.
+     */
+    public final void addPropertyChangeListener(
+            final String propertyName,
+            final PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * Remove property change listener.
+     * @param listener listener.
+     */
+    public final void removePropertyChangeListener(
+            final PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(listener);
+    }
+
+    /**
+     * Remove property change listener on a specific property.
+     * @param propertyName property name.
+     * @param listener listener.
+     */
+    public final void removePropertyChangeListener(
+            final String propertyName,
+            final PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * Fire a property change event to appropriate listeners.
+     * @param evt change event.
+     */
+    protected final void firePropertyChange(
+            final PropertyChangeEvent evt) {
+        propertySupport.firePropertyChange(evt);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final boolean oldValue,
+            final boolean newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final int oldValue, final int newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final Object oldValue,
+            final Object newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/Receiver.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/Receiver.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/Receiver.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/plugins/Receiver.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,131 @@
+/*
+ * 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.plugins;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.Thresholdable;
+
+
+/**
+ * Defines the base class for Receiver plugins.
+ * <p/>
+ * <p>Just as Appenders send logging events outside of the log4j
+ * environment (to files, to smtp, to sockets, etc), Receivers bring
+ * logging events inside the log4j environment.
+ * <p/>
+ * <p>Receivers are meant to support the receiving of
+ * remote logging events from another process. For example,
+ * SocketAppender "appends" a logging event to a socket, configured
+ * for a specific host and port number.  On the receiving side of
+ * the socket can be a SocketReceiver object.  The SocketReceiver
+ * object receives the logging event, and then "posts" it to the
+ * log4j environment (LoggerRepository) on the receiving machine, to
+ * be handled by the configured appenders, etc.  The various
+ * settings in this environment (Logger levels, Appender filters &
+ * thresholds) are applied to the received logging event.
+ * <p/>
+ * <p>Receivers can also be used to "import" log messages from other
+ * logging packages into the log4j environment.
+ * <p/>
+ * <p>Receivers can be configured to post events to a given
+ * LoggerRepository.
+ * <p/>
+ * <p>Subclasses of Receiver must implement the isActive(),
+ * activateOptions(), and shutdown() methods. The doPost() method
+ * is provided to standardize the "import" of remote events into
+ * the repository.
+ *
+ * @author Mark Womack
+ * @author Ceki G&uuml;lc&uuml;
+ * @author Paul Smith (psmith@apache.org)
+ */
+public abstract class Receiver extends PluginSkeleton implements Thresholdable {
+    /**
+     * Threshold level.
+     */
+    protected Level thresholdLevel;
+
+    /**
+     * Create new instance.
+     */
+    protected Receiver() {
+        super();
+    }
+
+    /**
+     * Sets the receiver theshold to the given level.
+     *
+     * @param level The threshold level events must equal or be greater
+     *              than before further processing can be done.
+     */
+    public void setThreshold(final Level level) {
+        Level oldValue = this.thresholdLevel;
+        thresholdLevel = level;
+        firePropertyChange("threshold", oldValue, this.thresholdLevel);
+    }
+
+    /**
+     * Gets the current threshold setting of the receiver.
+     *
+     * @return Level The current threshold level of the receiver.
+     */
+    public Level getThreshold() {
+        return thresholdLevel;
+    }
+
+    /**
+     * Returns true if the given level is equals or greater than the current
+     * threshold value of the receiver.
+     *
+     * @param level The level to test against the receiver threshold.
+     * @return boolean True if level is equal or greater than the
+     *         receiver threshold.
+     */
+    public boolean isAsSevereAsThreshold(final Level level) {
+        return ((thresholdLevel == null)
+                || level.isGreaterOrEqual(thresholdLevel));
+    }
+
+    /**
+     * Posts the logging event to a logger in the configured logger
+     * repository.
+     *
+     * @param event the log event to post to the local log4j environment.
+     */
+    public void doPost(final LoggingEvent event) {
+        // if event does not meet threshold, exit now
+        if (!isAsSevereAsThreshold(event.getLevel())) {
+            return;
+        }
+
+        // get the "local" logger for this event from the
+        // configured repository.
+        Logger localLogger =
+                getLoggerRepository().getLogger(event.getLoggerName());
+
+        // if the logger level is greater or equal to the level
+        // of the event, use the logger to append the event.
+        if (event.getLevel()
+                .isGreaterOrEqual(localLogger.getEffectiveLevel())) {
+            // call the loggers appenders to process the event
+            localLogger.callAppenders(event);
+        }
+  }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,85 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events where the message of the
+ * original event implementes java.util.Map.
+ * All other events are passed through unmodified.
+ * If the map contains a "message" entry, the value will be
+ * used as the message for the rewritten event.  The rewritten
+ * event will have a property set that is the combination of the
+ * original property set and the other members of the message map.
+ * If both the original property set and the message map
+ * contain the same entry, the value from the message map
+ * will overwrite the original property set.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the MapFilter from log4j 1.3. 
+ */
+public class MapRewritePolicy implements RewritePolicy {
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        Object msg = source.getMessage();
+        if (msg instanceof Map) {
+            Map props = new HashMap(source.getProperties());
+            Map eventProps = (Map) msg;
+            //
+            //   if the map sent in the logging request
+            //      has "message" entry, use that as the message body
+            //      otherwise, use the entire map.
+            //
+            Object newMsg = eventProps.get("message");
+            if (newMsg == null) {
+                newMsg = msg;
+            }
+
+            for(Iterator iter = eventProps.entrySet().iterator();
+                    iter.hasNext();
+                  ) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                if (!("message".equals(entry.getKey()))) {
+                    props.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            return new LoggingEvent(
+                    source.getFQNOfLoggerClass(),
+                    source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()), 
+                    source.getTimeStamp(),
+                    source.getLevel(),
+                    newMsg,
+                    source.getThreadName(),
+                    source.getThrowableInformation(),
+                    source.getNDC(),
+                    source.getLocationInformation(),
+                    props);
+        } else {
+            return source;
+        }
+
+    }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,93 @@
+/*
+ * 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 java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events by adding
+ * a user-specified list of properties to the event.
+ * Existing properties are not modified.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the PropertyFilter from log4j 1.3.
+ */
+
+public class PropertyRewritePolicy implements RewritePolicy {
+    private Map properties = Collections.EMPTY_MAP;
+    public PropertyRewritePolicy() {
+    }
+
+    /**
+     * Set a string representing the property name/value pairs.
+     * 
+     * Form: propname1=propvalue1,propname2=propvalue2
+     * 
+     * @param props
+     */
+    public void setProperties(String props) {
+        Map hashTable = new HashMap();
+        StringTokenizer pairs = new StringTokenizer(props, ",");
+        while (pairs.hasMoreTokens()) {
+            StringTokenizer entry = new StringTokenizer(pairs.nextToken(), "=");
+            hashTable.put(entry.nextElement().toString().trim(), entry.nextElement().toString().trim());
+        }
+        synchronized(this) {
+            properties = hashTable;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        if (!properties.isEmpty()) {
+            Map rewriteProps = new HashMap(source.getProperties());
+            for(Iterator iter = properties.entrySet().iterator();
+                    iter.hasNext();
+                    ) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                if (!rewriteProps.containsKey(entry.getKey())) {
+                    rewriteProps.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            return new LoggingEvent(
+                    source.getFQNOfLoggerClass(),
+                    source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()), 
+                    source.getTimeStamp(),
+                    source.getLevel(),
+                    source.getMessage(),
+                    source.getThreadName(),
+                    source.getThrowableInformation(),
+                    source.getNDC(),
+                    source.getLocationInformation(),
+                    rewriteProps);
+        }
+        return source;
+    }
+
+
+
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,89 @@
+/*
+ * 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 java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events by evaluating any
+ * JavaBean properties on the message object and adding them
+ * to the event properties.  If the message object has a
+ * message property, the value of that property will be
+ * used as the message for the rewritten event and will
+ * not be added to the event properties.  Values from the
+ * JavaBean properties will replace any existing property
+ * with the same name.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the ReflectionFilter from log4j 1.3. 
+ */
+public class ReflectionRewritePolicy implements RewritePolicy {
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        Object msg = source.getMessage();
+        if (!(msg instanceof String)) {
+            Object newMsg = msg;
+            Map rewriteProps = new HashMap(source.getProperties());
+
+            try {
+                PropertyDescriptor[] props = Introspector.getBeanInfo(
+                        msg.getClass(), Object.class).getPropertyDescriptors();
+                if (props.length > 0) {
+                    for (int i=0;i<props.length;i++) {
+                        try {
+                            Object propertyValue =
+                                props[i].getReadMethod().invoke(msg,
+                                        (Object[]) null);
+                            if ("message".equalsIgnoreCase(props[i].getName())) {
+                                newMsg = propertyValue;
+                            } else {
+                                rewriteProps.put(props[i].getName(), propertyValue);
+                            }
+                        } catch (Exception e) {
+                            LogLog.warn("Unable to evaluate property " +
+                                    props[i].getName(), e);
+                        }
+                    }
+                    return new LoggingEvent(
+                            source.getFQNOfLoggerClass(),
+                            source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()),
+                            source.getTimeStamp(),
+                            source.getLevel(),
+                            newMsg,
+                            source.getThreadName(),
+                            source.getThrowableInformation(),
+                            source.getNDC(),
+                            source.getLocationInformation(),
+                            rewriteProps);
+                }
+            } catch (Exception e) {
+                LogLog.warn("Unable to get property descriptors", e);
+            }
+
+        }
+        return source;
+    }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,199 @@
+/*
+ * 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;
+    }
+
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,37 @@
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+/*
+* 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.
+*/
+
+/**
+ * This interface is implemented to provide a rewrite
+ * strategy for RewriteAppender.  RewriteAppender will
+ * call the rewrite method with a source logging event.
+ * The strategy may return that event, create a new event
+ * or return null to suppress the logging request.
+ */
+public interface RewritePolicy {
+    /**
+     * Rewrite a logging event.
+     * @param source a logging event that may be returned or
+     * used to create a new logging event.
+     * @return a logging event or null to suppress processing.
+     */
+    LoggingEvent rewrite(final LoggingEvent source);
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Job.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Job.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Job.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Job.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,36 @@
+/*
+ * 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.scheduler;
+
+
+/**
+ * Job is a very simple interface. It only has a single method {@link #execute}
+ * which is called by the {@link Scheduler} when a task is ready for execution.
+ * <p/>
+ * It is assumed that the execution context
+ * are contained within the implementing
+ * {@link Job} itself.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public interface Job {
+    /**
+     * Execute job.
+     */
+    void execute();
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Scheduler.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Scheduler.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Scheduler.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/scheduler/Scheduler.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,307 @@
+/*
+ * 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.scheduler;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A simple but still useful implementation of a Scheduler (in memory only).
+ * <p/>
+ * This implementation will work very well when the number of scheduled job is
+ * small, say less than 100 jobs. If a larger number of events need to be
+ * scheduled, than a better adapted data structure for the jobList can give
+ * improved performance.
+ *
+ * @author Ceki
+ */
+public class Scheduler extends Thread {
+
+    /**
+     * Job list.
+     */
+    List jobList;
+    /**
+     * If set true, scheduler has or should shut down.
+     */
+    boolean shutdown = false;
+
+    /**
+     * Create new instance.
+     */
+    public Scheduler() {
+        super();
+        jobList = new Vector();
+    }
+
+    /**
+     * Find the index of a given job.
+     * @param job job
+     * @return -1 if the job could not be found.
+     */
+    int findIndex(final Job job) {
+        int size = jobList.size();
+        boolean found = false;
+
+        int i = 0;
+        for (; i < size; i++) {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.get(i);
+            if (se.job == job) {
+                found = true;
+                break;
+            }
+        }
+        if (found) {
+            return i;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Delete the given job.
+     * @param job job.
+     * @return true if the job could be deleted, and
+     * false if the job could not be found or if the Scheduler is about to
+     * shutdown in which case deletions are not permitted.
+     */
+    public synchronized boolean delete(final Job job) {
+        // if already shutdown in the process of shutdown, there is no
+        // need to remove Jobs as they will never be executed.
+        if (shutdown) {
+            return false;
+        }
+        int i = findIndex(job);
+        if (i != -1) {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.remove(i);
+            if (se.job != job) { // this should never happen
+                new IllegalStateException("Internal programming error");
+            }
+            // if the job is the first on the list,
+            // then notify the scheduler thread to schedule a new job
+            if (i == 0) {
+                this.notifyAll();
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Schedule a {@link Job} for execution at system time given by
+     * the <code>desiredTime</code> parameter.
+     * @param job job to schedule.
+     * @param desiredTime desired time of execution.
+     */
+    public synchronized void schedule(final Job job,
+                                      final long desiredTime) {
+        schedule(new ScheduledJobEntry(job, desiredTime));
+    }
+
+    /**
+     * Schedule a {@link Job} for execution at system time given by
+     * the <code>desiredTime</code> parameter.
+     * <p/>
+     * The job will be rescheduled. It will execute with a frequency determined
+     * by the period parameter.
+     * @param job job to schedule.
+     * @param desiredTime desired time of execution.
+     * @param period repeat period.
+     */
+    public synchronized void schedule(final Job job,
+                                      final long desiredTime,
+                                      final long period) {
+        schedule(new ScheduledJobEntry(job, desiredTime, period));
+    }
+
+    /**
+     * Change the period of a job. The original job must exist for its period
+     * to be changed.
+     * <p/>
+     * The method returns true if the period could be changed, and false
+     * otherwise.
+     * @param job job.
+     * @param newPeriod new repeat period.
+     * @return true if period could be changed.
+     */
+    public synchronized boolean changePeriod(final Job job,
+                                             final long newPeriod) {
+        if (newPeriod <= 0) {
+            throw new IllegalArgumentException(
+                    "Period must be an integer langer than zero");
+        }
+
+        int i = findIndex(job);
+        if (i == -1) {
+            return false;
+        } else {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.get(i);
+            se.period = newPeriod;
+            return true;
+        }
+    }
+
+    /**
+     * Schedule a job.
+     * @param newSJE new job entry.
+     */
+    private synchronized void schedule(final ScheduledJobEntry newSJE) {
+        // disallow new jobs after shutdown
+        if (shutdown) {
+            return;
+        }
+        int max = jobList.size();
+        long desiredExecutionTime = newSJE.desiredExecutionTime;
+
+        // find the index i such that timeInMillis < jobList[i]
+        int i = 0;
+        for (; i < max; i++) {
+
+            ScheduledJobEntry sje = (ScheduledJobEntry) jobList.get(i);
+
+            if (desiredExecutionTime < sje.desiredExecutionTime) {
+                break;
+            }
+        }
+        jobList.add(i, newSJE);
+        // if the jobList was empty, then notify the scheduler thread
+        if (i == 0) {
+            this.notifyAll();
+        }
+    }
+
+    /**
+     * Shut down scheduler.
+     */
+    public synchronized void shutdown() {
+        shutdown = true;
+    }
+
+    /**
+     * Run scheduler.
+     */
+    public synchronized void run() {
+        while (!shutdown) {
+            if (jobList.isEmpty()) {
+                linger();
+            } else {
+                ScheduledJobEntry sje = (ScheduledJobEntry) jobList.get(0);
+                long now = System.currentTimeMillis();
+                if (now >= sje.desiredExecutionTime) {
+                    executeInABox(sje.job);
+                    jobList.remove(0);
+                    if (sje.period > 0) {
+                        sje.desiredExecutionTime = now + sje.period;
+                        schedule(sje);
+                    }
+                } else {
+                    linger(sje.desiredExecutionTime - now);
+                }
+            }
+        }
+        // clear out the job list to facilitate garbage collection
+        jobList.clear();
+        jobList = null;
+        System.out.println("Leaving scheduler run method");
+    }
+
+    /**
+     * We do not want a single failure to affect the whole scheduler.
+     * @param job job to execute.
+     */
+    void executeInABox(final Job job) {
+        try {
+            job.execute();
+        } catch (Exception e) {
+            System.err.println("The execution of the job threw an exception");
+            e.printStackTrace(System.err);
+        }
+    }
+
+    /**
+     * Wait for notification.
+     */
+    void linger() {
+        try {
+            while (jobList.isEmpty() && !shutdown) {
+                this.wait();
+            }
+        } catch (InterruptedException ie) {
+            shutdown = true;
+        }
+    }
+
+    /**
+     * Wait for notification or time to elapse.
+     * @param timeToLinger time to linger.
+     */
+    void linger(final long timeToLinger) {
+        try {
+            this.wait(timeToLinger);
+        } catch (InterruptedException ie) {
+            shutdown = true;
+        }
+    }
+
+    /**
+     * Represents an entry in job scheduler.
+     */
+    static final class ScheduledJobEntry {
+        /**
+         * Desired execution time.
+         */
+        long desiredExecutionTime;
+        /**
+         * Job to run.
+         */
+        Job job;
+        /**
+         * Repeat period.
+         */
+        long period = 0;
+
+        /**
+         * Create new instance.
+         * @param job job
+         * @param desiredTime desired time.
+         */
+        ScheduledJobEntry(final Job job, final long desiredTime) {
+            this(job, desiredTime, 0);
+        }
+
+        /**
+         * Create new instance.
+         * @param job job
+         * @param desiredTime desired time
+         * @param period repeat period
+         */
+        ScheduledJobEntry(final Job job,
+                          final long desiredTime,
+                          final long period) {
+            super();
+            this.desiredExecutionTime = desiredTime;
+            this.job = job;
+            this.period = period;
+        }
+    }
+
+}
+
+

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Component.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Component.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Component.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Component.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,37 @@
+/*
+ * 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.spi;
+
+
+/**
+ * A common interface shared by log4j components.
+ *
+ * @author Ceki Gulcu
+ */
+public interface Component {
+
+
+    /**
+     * Set owning logger repository for this component. This operation can
+     * only be performed once.
+     * Once set, a subsequent attempt will throw an IllegalStateException.
+     *
+     * @param repository The repository where this appender is attached.
+     */
+    void setLoggerRepository(LoggerRepository repository);
+
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ComponentBase.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ComponentBase.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ComponentBase.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ComponentBase.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,126 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.ULogger;
+import org.apache.log4j.Logger;
+
+
+/**
+ * Most log4j components derive from this class.
+ *
+ * @author Ceki Gulcu
+ */
+public class ComponentBase implements Component {
+
+    /**
+     * Error count limit.
+     */
+    private static final int ERROR_COUNT_LIMIT = 3;
+
+    /**
+     * Logger repository.
+     */
+    protected LoggerRepository repository;
+    /**
+     * Logger.
+     */
+    private ULogger logger;
+    /**
+     * Error count.
+     */
+    private int errorCount = 0;
+
+    /**
+     * Construct a new instance.
+     */
+    protected ComponentBase() {
+        super();
+    }
+
+
+    /**
+     * Called by derived classes when they deem that the component has recovered
+     * from an erroneous state.
+     */
+    protected void resetErrorCount() {
+        errorCount = 0;
+    }
+
+    /**
+     * Set the owning repository. The owning repository cannot be set more than
+     * once.
+     *
+     * @param repository repository
+     */
+    public void setLoggerRepository(final LoggerRepository repository) {
+        if (this.repository == null) {
+            this.repository = repository;
+        } else if (this.repository != repository) {
+            throw new IllegalStateException("Repository has been already set");
+        }
+    }
+
+    /**
+     * Return the LoggerRepository to which this component is attached.
+     *
+     * @return Owning LoggerRepository
+     */
+    protected LoggerRepository getLoggerRepository() {
+        return repository;
+    }
+
+    /**
+     * Return an instance specific logger to be used by the component itself.
+     * This logger is not intended to be accessed by the end-user, hence the
+     * protected keyword.
+     * <p/>
+     * <p>In case the repository for this component is not set,
+     * this implementations returns a {@link SimpleULogger} instance.
+     *
+     * @return A ULogger instance.
+     */
+    protected ULogger getLogger() {
+        if (logger == null) {
+            if (repository != null) {
+                Logger l = repository.getLogger(this.getClass().getName());
+                if (l instanceof ULogger) {
+                    logger = (ULogger) l;
+                } else {
+                    logger = new Log4JULogger(l);
+                }
+            } else {
+                logger = SimpleULogger.getLogger(this.getClass().getName());
+            }
+        }
+        return logger;
+    }
+
+    /**
+     * Frequently called methods in log4j components can invoke this method in
+     * order to avoid flooding the output when logging lasting error conditions.
+     *
+     * @return a regular logger, or a NOPLogger if called too frequently.
+     */
+    protected ULogger getNonFloodingLogger() {
+        if (errorCount++ >= ERROR_COUNT_LIMIT) {
+            return NOPULogger.NOP_LOGGER;
+        } else {
+            return getLogger();
+    }
+  }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ErrorItem.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ErrorItem.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ErrorItem.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/ErrorItem.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,172 @@
+/*
+ * 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.spi;
+
+import java.io.PrintStream;
+
+/**
+ * Used to store special log4j errors which cannot be logged using internal
+ * logging. Such errors include those occurring during the initial phases
+ * of log4j configuration or errors emanating from core components such as
+ * Logger or Hierarchy.
+ *
+ * @author Ceki Gulcu
+ */
+public class ErrorItem {
+    /**
+     * Message.
+     */
+  String message;
+    /**
+     * Column.
+     */
+  int colNumber = -1;
+    /**
+     * Line number.
+     */
+  int lineNumber = -1;
+    /**
+     * Exception.
+     */
+  Throwable exception;
+
+    /**
+     * Create new instance.
+     * @param message message
+     * @param e exception
+     */
+  public ErrorItem(final String message, final Exception e) {
+    super();
+    this.message = message;
+    exception = e;
+  }
+
+    /**
+     * Creaet new instance.
+     * @param message message.
+     */
+  public ErrorItem(final String message) {
+    this(message, null);
+  }
+
+    /**
+     * Get column number.
+     * @return column number.
+     */
+  public int getColNumber() {
+    return colNumber;
+  }
+
+    /**
+     * Set column number.
+     * @param colNumber new column number.
+     */
+  public void setColNumber(int colNumber) {
+    this.colNumber = colNumber;
+  }
+
+    /**
+     * Get exception.
+     * @return exception.
+     */
+  public Throwable getException() {
+    return exception;
+  }
+
+    /**
+     * Set exception.
+     * @param exception exception
+     */
+  public void setException(final Throwable exception) {
+    this.exception = exception;
+  }
+
+    /**
+     * Get line number.
+     * @return line number.
+     */
+  public int getLineNumber() {
+    return lineNumber;
+  }
+
+    /**
+     * Set line number.
+     * @param lineNumber line number.
+     */
+  public void setLineNumber(final int lineNumber) {
+    this.lineNumber = lineNumber;
+  }
+
+    /**
+     * Get message.
+     * @return message.
+     */
+  public String getMessage() {
+    return message;
+  }
+
+    /**
+     * Set message.
+     * @param message message.
+     */
+  public void setMessage(final String message) {
+    this.message = message;
+  }
+
+    /**
+     * String representation of ErrorItem.
+     * @return string.
+     */
+  public String toString() {
+    String str =
+      "Reported error: \"" + message + "\"";
+
+    if (lineNumber != -1) {
+      str += " at line " + lineNumber + " column " + colNumber;
+    }
+    if (exception != null) {
+      str += (" with exception " + exception);
+    }
+    return str;
+  }
+
+  /**
+   * Dump the details of this ErrorItem to System.out.
+   */
+  public void dump() {
+    dump(System.out);
+  }
+  
+  /**
+   * Dump the details of this ErrorItem on the specified {@link PrintStream}.
+   * @param ps print stream.
+   */
+  public void dump(final PrintStream ps) {
+    String str =
+      "Reported error: \"" + message + "\"";
+
+    if (lineNumber != -1) {
+      str += " at line " + lineNumber + " column " + colNumber;
+    }
+    ps.println(str);
+
+    if (exception != null) {
+      exception.printStackTrace(ps);
+    }
+  }
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Log4JULogger.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Log4JULogger.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Log4JULogger.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/Log4JULogger.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,229 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.ULogger;
+import org.apache.log4j.helpers.MessageFormatter;
+import org.apache.log4j.Level;
+
+
+/**
+ * An implementation of ULogger on org.apache.log4j.Logger.
+ */
+public final class Log4JULogger implements ULogger {
+
+    /**
+     * Wrapped log4j logger.
+     */
+    private final Logger logger;
+
+    /**
+     * Create a new instance.
+     *
+     * @param l logger, may not be null.
+     */
+    public Log4JULogger(final Logger l) {
+        super();
+        if (l == null) {
+            throw new NullPointerException("l");
+        }
+        logger = l;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDebugEnabled() {
+        return logger.isDebugEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg) {
+        logger.debug(msg);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object parameterizedMsg,
+                      final Object param1) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg,
+                      final Throwable t) {
+        logger.debug(msg, t);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInfoEnabled() {
+        return logger.isInfoEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg) {
+        logger.info(msg);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object parameterizedMsg,
+                     final Object param1) {
+        if (logger.isInfoEnabled()) {
+            logger.info(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        if (logger.isInfoEnabled()) {
+            logger.info(MessageFormatter.format(
+                    parameterizedMsg.toString(),
+                    param1,
+                    param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg, final Throwable t) {
+        logger.info(msg, t);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isWarnEnabled() {
+        return logger.isEnabledFor(Level.WARN);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg) {
+        logger.warn(msg);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object parameterizedMsg,
+                     final Object param1) {
+        if (logger.isEnabledFor(Level.WARN)) {
+            logger.warn(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        if (logger.isEnabledFor(Level.WARN)) {
+            logger.warn(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg, final Throwable t) {
+        logger.warn(msg, t);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isErrorEnabled() {
+        return logger.isEnabledFor(Level.ERROR);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg) {
+        logger.error(msg);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object parameterizedMsg, final Object param1) {
+        if (logger.isEnabledFor(Level.ERROR)) {
+            logger.error(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        if (logger.isEnabledFor(Level.ERROR)) {
+            logger.error(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg, final Throwable t) {
+        logger.error(msg, t);
+    }
+
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerEventListener.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerEventListener.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerEventListener.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerEventListener.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,59 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Logger;
+
+
+/**
+  Interface used to listen for Logger related events such as
+  add/remove appender or changing levels.  Clients register an instance of
+  the interface and the instance is called back when the various events occur.
+
+  LoggerRepository provides methods for adding and removing
+  LoggerEventListener instances.
+
+  When implementing the methods of this interface, it is useful to remember
+  that the Logger can access the repository using its getRepository()
+  method.
+
+  @author Ceki G&uuml;lc&uuml;
+  @author Mark Womack
+*/
+public interface LoggerEventListener {
+  /**
+    Called when an appender is added to the logger.
+
+    @param logger The logger to which the appender was added.
+    @param appender The appender added to the logger. */
+  void appenderAddedEvent(Logger logger, Appender appender);
+
+  /**
+    Called when an appender is removed from the logger.
+
+    @param logger The logger from which the appender was removed.
+    @param appender The appender removed from the logger. */
+  void appenderRemovedEvent(Logger logger, Appender appender);
+
+  /**
+    Called when level changed on the logger.
+
+    @param logger The logger that changed levels. */
+  void levelChangedEvent(Logger logger);
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,53 @@
+/*
+ * 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.spi;
+
+
+/**
+  Interface used to listen for LoggerRepository related
+  events such as startup, reset, and shutdown.  Clients register
+  an instance of the interface and the instance is called back
+  when the various events occur.
+
+  LoggerRepository provides methods for adding and removing
+  LoggerRepositoryEventListener instances.
+
+  @author Ceki G&uuml;lc&uuml;
+  @author Mark Womack
+*/
+public interface LoggerRepositoryEventListener {
+  /**
+    Called when the repository configuration is reset.
+   @param repository repository
+   */
+  void configurationResetEvent(LoggerRepository repository);
+
+  /**
+    Called when the repository configuration is changed.
+   @param repository repository
+   */
+  void configurationChangedEvent(LoggerRepository repository);
+
+  /**
+    Called when the repository is shutdown. When this method is
+    invoked, the repository is still valid (ie it has not been
+    shutdown, but will be after this method returns).
+    @param repository repository.
+   */
+  void shutdownEvent(LoggerRepository repository);
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,198 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.scheduler.Scheduler;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+   A <code>LoggerRepository</code> is used to create and retrieve
+   <code>Loggers</code>. The relation between loggers in a repository
+   depends on the repository but typically loggers are arranged in a
+   named hierarchy.
+
+   <p>In addition to the creational methods, a
+   <code>LoggerRepository</code> can be queried for existing loggers,
+   can act as a point of registry for events related to loggers.
+
+   @author Ceki G&uuml;lc&uuml;
+   @author Mark Womack
+   @author Curt Arnold
+   */
+public interface LoggerRepositoryEx extends LoggerRepository {
+  /**
+    Add a {@link LoggerRepositoryEventListener} to the repository. The
+    listener will be called when repository events occur.
+     @param listener event listener, may not be null.
+    */
+  void addLoggerRepositoryEventListener(
+    LoggerRepositoryEventListener listener);
+
+  /**
+    Remove a {@link LoggerRepositoryEventListener} from the repository.
+   @param listener listener.
+    */
+  void removeLoggerRepositoryEventListener(
+    LoggerRepositoryEventListener listener);
+
+  /**
+    Add a {@link LoggerEventListener} to the repository. The  listener
+    will be called when repository events occur.
+   @param listener listener, may not be null.
+    */
+  void addLoggerEventListener(LoggerEventListener listener);
+
+  /**
+    Remove a {@link LoggerEventListener} from the repository.
+   @param listener listener, may not be null.
+    */
+  void removeLoggerEventListener(LoggerEventListener listener);
+
+  /**
+   * Get the name of this logger repository.
+   * @return name, may not be null.
+   */
+  String getName();
+
+  /**
+   * A logger repository is a named entity.
+   * @param repoName new name, may not be null.
+   */
+  void setName(String repoName);
+
+  /**
+   * Is the current configuration of the repository in its original (pristine)
+   * state?
+   * @return true if repository is in original state.
+   *
+   */
+  boolean isPristine();
+
+  /**
+   *  Set the pristine flag.
+   * @param state state
+   *  @see #isPristine
+   */
+  void setPristine(boolean state);
+
+  /**
+    Requests that a appender removed event be sent to any registered
+    {@link LoggerEventListener}.
+    @param logger The logger from which the appender was removed.
+    @param appender The appender removed from the logger.
+    */
+  void fireRemoveAppenderEvent(Category logger, Appender appender);
+
+  /**
+    Requests that a level changed event be sent to any registered
+    {@link LoggerEventListener}.
+    @param logger The logger which changed levels.
+    */
+  void fireLevelChangedEvent(Logger logger);
+
+  /**
+    Requests that a configuration changed event be sent to any registered
+    {@link LoggerRepositoryEventListener}.
+    */
+  void fireConfigurationChangedEvent();
+
+  /**
+   * Return the PluginRegisty for this LoggerRepository.
+   * @return plug in registry.
+   */
+  PluginRegistry getPluginRegistry();
+
+  /**
+   * Return the {@link Scheduler} for this LoggerRepository.
+   * @return scheduler.
+   */
+  Scheduler getScheduler();
+
+  /**
+   * Get the properties specific for this repository.
+   * @return property map.
+   */
+  Map getProperties();
+
+  /**
+   * Get the property of this repository.
+   * @param key property key.
+   * @return key value or null if not set.
+   */
+  String getProperty(String key);
+
+  /**
+   * Set a property of this repository.
+   * @param key key, may not be null.
+   * @param value new value, if null, property will be removed.
+   */
+  void setProperty(String key, String value);
+
+  /**
+   * Errors which cannot be logged, go to the error list.
+   *
+   * @return List
+   */
+  List getErrorList();
+
+  /**
+   * Errors which cannot be logged, go to the error list.
+   *
+   * @param errorItem an ErrorItem to add to the error list
+   */
+  void addErrorItem(ErrorItem errorItem);
+
+  /**
+   * A LoggerRepository can also act as a store for various objects used
+   * by log4j components.
+   *
+   * @param key key, may not be null.
+   * @return The object stored under 'key'.
+   */
+  Object getObject(String key);
+
+  /**
+   * Store an object under 'key'. If no object can be found, null is returned.
+   *
+   * @param key key, may not be null.
+   * @param value value, may be null.
+   */
+  void putObject(String key, Object value);
+
+  /**
+   * Sets the logger factory used by LoggerRepository.getLogger(String).
+   * @param loggerFactory factory to use, may not be null
+   */
+  void setLoggerFactory(LoggerFactory loggerFactory);
+
+  /**
+   * Returns the logger factory used by
+   * LoggerRepository.getLogger(String).
+   *
+   * @return non-null factory
+   */
+  LoggerFactory getLoggerFactory();
+
+}

Added: logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/NOPULogger.java
URL: http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/NOPULogger.java?rev=1178304&view=auto
==============================================================================
--- logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/NOPULogger.java (added)
+++ logging/chainsaw/trunk/src/main/java/org/apache/log4j/spi/NOPULogger.java Mon Oct  3 06:15:40 2011
@@ -0,0 +1,200 @@
+/*
+ * 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.spi;
+
+import org.apache.log4j.ULogger;
+
+
+/**
+ * A no operation (NOP) implementation of {@link ULogger}.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public final class NOPULogger implements ULogger {
+
+    /**
+     * The unique instance of NOPLogger.
+     */
+    public static final NOPULogger NOP_LOGGER = new NOPULogger();
+
+    /**
+     * There is no point in people creating multiple instances of NullLogger.
+     * Hence, the private access modifier.
+     */
+    private NOPULogger() {
+        super();
+    }
+
+    /**
+     * Get instance.
+     * @param name logger name.
+     * @return logger.
+     */
+    public static NOPULogger getLogger(final String name) {
+        return NOP_LOGGER;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDebugEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInfoEnabled() {
+        // NOP
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final String parameterizedMsg,
+                     final Object param1, final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isWarnEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object parameterizedMsg,
+                     final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isErrorEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+}



Mime
View raw message