You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2017/05/30 23:49:12 UTC
[35/50] [abbrv] logging-chainsaw git commit: Moved component and
receivers companion sources to the Chainsaw source tree - those companions
won't be released.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
new file mode 100644
index 0000000..cd37dc4
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
@@ -0,0 +1,316 @@
+/*
+ * 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.net;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+ XMLSocketReceiver receives a remote logging event via XML on a configured
+ socket and "posts" it to a LoggerRepository as if the event were
+ generated locally. This class is designed to receive events from
+ the XMLSocketAppender class (or classes that send compatible events).
+ <p>
+ This receiver supports log files created using log4j's XMLLayout, as well as java.util.logging
+ XMLFormatter (via the org.apache.log4j.spi.Decoder interface).
+ <p>
+ By default, log4j's XMLLayout is supported (no need to specify a decoder in that case).
+ <p>
+ To configure this receiver to support java.util.logging's XMLFormatter, specify a 'decoder' param
+ of org.apache.log4j.xml.UtilLoggingXMLDecoder.
+ <p>
+ Once the event has been "posted", it will be handled by the
+ appenders currently configured in the LoggerRespository.
+
+ @author Mark Womack
+ @author Scott Deboy <sd...@apache.org>
+
+*/
+public class XMLSocketReceiver extends Receiver implements Runnable, PortBased, Pauseable {
+ private boolean paused;
+ //default to log4j xml decoder
+ protected String decoder = "org.apache.log4j.xml.XMLDecoder";
+ private ServerSocket serverSocket;
+ private List socketList = new Vector();
+ private Thread rThread;
+ public static final int DEFAULT_PORT = 4448;
+ protected int port = DEFAULT_PORT;
+ private boolean advertiseViaMulticastDNS;
+ private ZeroConfSupport zeroConf;
+
+ /**
+ * The MulticastDNS zone advertised by an XMLSocketReceiver
+ */
+ public static final String ZONE = "_log4j_xml_tcpaccept_receiver.local.";
+
+ /*
+ * Log4j doesn't provide an XMLSocketAppender, but the MulticastDNS zone that should be advertised by one is:
+ * _log4j_xml_tcpconnect_appender.local.
+ */
+
+ public XMLSocketReceiver() {
+ }
+
+ public XMLSocketReceiver(int _port) {
+ port = _port;
+ }
+
+ public XMLSocketReceiver(int _port, LoggerRepository _repository) {
+ port = _port;
+ repository = _repository;
+ }
+
+ /**
+ Get the port to receive logging events on. */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ Set the port to receive logging events on. */
+ public void setPort(int _port) {
+ port = _port;
+ }
+
+ public String getDecoder() {
+ return decoder;
+ }
+
+ /**
+ *Specify the class name implementing org.apache.log4j.spi.Decoder that can process the file.
+ */
+ public void setDecoder(String _decoder) {
+ decoder = _decoder;
+ }
+
+ public boolean isPaused() {
+ return paused;
+ }
+
+ public void setPaused(boolean b) {
+ paused = b;
+ }
+
+ /**
+ * Returns true if the receiver is the same class and they are
+ * configured for the same properties, and super class also considers
+ * them to be equivalent. This is used by PluginRegistry when determining
+ * if the a similarly configured receiver is being started.
+ *
+ * @param testPlugin The plugin to test equivalency against.
+ * @return boolean True if the testPlugin is equivalent to this plugin.
+ */
+ public boolean isEquivalent(Plugin testPlugin) {
+ if ((testPlugin != null) && testPlugin instanceof XMLSocketReceiver) {
+ XMLSocketReceiver sReceiver = (XMLSocketReceiver) testPlugin;
+
+ return (port == sReceiver.getPort() && super.isEquivalent(testPlugin));
+ }
+
+ return false;
+ }
+
+ public int hashCode() {
+
+ int result = 37 * (repository != null? repository.hashCode():0);
+ result = result * 37 + port;
+ return (result * 37 + (getName() != null? getName().hashCode():0));
+ }
+
+ /**
+ Sets the flag to indicate if receiver is active or not.
+ @param b new value
+ */
+ protected synchronized void setActive(final boolean b) {
+ active = b;
+ }
+
+ /**
+ Starts the SocketReceiver with the current options. */
+ public void activateOptions() {
+ if (!isActive()) {
+ rThread = new Thread(this);
+ rThread.setDaemon(true);
+ rThread.start();
+
+ if (advertiseViaMulticastDNS) {
+ zeroConf = new ZeroConfSupport(ZONE, port, getName());
+ zeroConf.advertise();
+ }
+
+ active = true;
+ }
+ }
+
+ public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+ this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+ }
+
+ public boolean isAdvertiseViaMulticastDNS() {
+ return advertiseViaMulticastDNS;
+ }
+
+ /**
+ Called when the receiver should be stopped. Closes the
+ server socket and all of the open sockets. */
+ public synchronized void shutdown() {
+ // mark this as no longer running
+ active = false;
+
+ if (rThread != null) {
+ rThread.interrupt();
+ rThread = null;
+ }
+ doShutdown();
+ }
+
+ /**
+ * Does the actual shutting down by closing the server socket
+ * and any connected sockets that have been created.
+ */
+ private synchronized void doShutdown() {
+ active = false;
+
+ getLogger().debug("{} doShutdown called", getName());
+
+ // close the server socket
+ closeServerSocket();
+
+ // close all of the accepted sockets
+ closeAllAcceptedSockets();
+
+ if (advertiseViaMulticastDNS) {
+ zeroConf.unadvertise();
+ }
+ }
+
+ /**
+ * Closes the server socket, if created.
+ */
+ private void closeServerSocket() {
+ getLogger().debug("{} closing server socket", getName());
+
+ try {
+ if (serverSocket != null) {
+ serverSocket.close();
+ }
+ } catch (Exception e) {
+ // ignore for now
+ }
+
+ serverSocket = null;
+ }
+
+ /**
+ * Closes all the connected sockets in the List.
+ */
+ private synchronized void closeAllAcceptedSockets() {
+ for (int x = 0; x < socketList.size(); x++) {
+ try {
+ ((Socket) socketList.get(x)).close();
+ } catch (Exception e) {
+ // ignore for now
+ }
+ }
+
+ // clear member variables
+ socketList.clear();
+ }
+
+ /**
+ Loop, accepting new socket connections. */
+ public void run() {
+ /**
+ * Ensure we start fresh.
+ */
+ getLogger().debug("performing socket cleanup prior to entering loop for {}", name);
+ closeServerSocket();
+ closeAllAcceptedSockets();
+ getLogger().debug("socket cleanup complete for {}", name);
+ active = true;
+
+ // start the server socket
+ try {
+ serverSocket = new ServerSocket(port);
+ } catch (Exception e) {
+ getLogger().error(
+ "error starting SocketReceiver (" + this.getName()
+ + "), receiver did not start", e);
+ active = false;
+ doShutdown();
+
+ return;
+ }
+
+ Socket socket = null;
+
+ try {
+ getLogger().debug("in run-about to enter while isactiveloop");
+
+ active = true;
+
+ while (!rThread.isInterrupted()) {
+ // if we have a socket, start watching it
+ if (socket != null) {
+ getLogger().debug("socket not null - creating and starting socketnode");
+ socketList.add(socket);
+
+ XMLSocketNode node = new XMLSocketNode(decoder, socket, this);
+ node.setLoggerRepository(this.repository);
+ new Thread(node).start();
+ socket = null;
+ }
+
+ getLogger().debug("waiting to accept socket");
+
+ // wait for a socket to open, then loop to start it
+ socket = serverSocket.accept();
+ getLogger().debug("accepted socket");
+ }
+
+ // socket not watched because we a no longer running
+ // so close it now.
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (Exception e) {
+ getLogger().warn(
+ "socket server disconnected, stopping");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.log4j.plugins.Receiver#doPost(org.apache.log4j.spi.LoggingEvent)
+ */
+ public void doPost(LoggingEvent event) {
+ if(!isPaused()){
+ super.doPost(event);
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Pauseable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Pauseable.java b/src/main/java/org/apache/log4j/plugins/Pauseable.java
new file mode 100644
index 0000000..6268ba3
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Pauseable.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+
+/**
+ * Instances of this interface can be paused, and resumed.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public interface Pauseable {
+ /**
+ * Set paused state.
+ * @param paused new value
+ */
+ void setPaused(boolean paused);
+
+ /**
+ * Get paused state.
+ * @return paused state.
+ */
+ boolean isPaused();
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Plugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Plugin.java b/src/main/java/org/apache/log4j/plugins/Plugin.java
new file mode 100644
index 0000000..e1b6a6f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Plugin.java
@@ -0,0 +1,144 @@
+/*
+ * 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.LoggerRepository;
+import org.apache.log4j.spi.OptionHandler;
+
+import java.beans.PropertyChangeListener;
+
+
+/**
+ * Defines the required interface for all Plugin objects.
+ * <p/>
+ * <p>A plugin implements some specific functionality to extend
+ * the log4j framework. Each plugin is associated with a specific
+ * LoggerRepository, which it then uses/acts upon. The functionality
+ * of the plugin is up to the developer.
+ * <p/>
+ * <p>Examples of plugins are Receiver and Watchdog. Receiver plugins
+ * allow for remote logging events to be received and processed by
+ * a repository as if the event was sent locally. Watchdog plugins
+ * allow for a repository to be reconfigured when some "watched"
+ * configuration data changes.
+ *
+ * @author Mark Womack (mwomack@apache.org)
+ * @author Nicko Cadell
+ * @author Paul Smith (psmith@apache.org)
+ */
+public interface Plugin extends OptionHandler {
+ /**
+ * Gets the name of the plugin.
+ *
+ * @return String the name of the plugin.
+ */
+ String getName();
+
+ /**
+ * Sets the name of the plugin.
+ *
+ * @param name the name of the plugin.
+ */
+ void setName(String name);
+
+ /**
+ * Gets the logger repository for this plugin.
+ *
+ * @return the logger repository to which this plugin is attached.
+ */
+ LoggerRepository getLoggerRepository();
+
+ /**
+ * Sets the logger repository used by this plugin. This
+ * repository will be used by the plugin functionality.
+ *
+ * @param repository the logger repository to attach this plugin to.
+ */
+ void setLoggerRepository(LoggerRepository repository);
+
+ /**
+ * Adds a PropertyChangeListener to this instance which is
+ * notified only by changes of the property with name propertyName.
+ *
+ * @param propertyName
+ * the name of the property in standard JavaBean syntax
+ * (e.g. for setName(), property="name")
+ * @param l listener
+ */
+ void addPropertyChangeListener(
+ String propertyName, PropertyChangeListener l);
+
+ /**
+ * Adds a PropertyChangeListener that will be notified of all property
+ * changes.
+ *
+ * @param l The listener to add.
+ */
+ void addPropertyChangeListener(PropertyChangeListener l);
+
+ /**
+ * Removes a specific PropertyChangeListener from this instances
+ * registry that has been mapped to be notified of all property
+ * changes.
+ *
+ * @param l The listener to remove.
+ */
+ void removePropertyChangeListener(PropertyChangeListener l);
+
+ /**
+ * Removes a specific PropertyChangeListener from this instance's
+ * registry which has been previously registered to be notified
+ * of only a specific property change.
+ *
+ * @param propertyName property name, may not be null.
+ * @param l listener to be removed.
+ */
+ void removePropertyChangeListener(
+ String propertyName, PropertyChangeListener l);
+
+ /**
+ * True if the plugin is active and running.
+ *
+ * @return boolean true if the plugin is currently active.
+ */
+ boolean isActive();
+
+ /**
+ * Returns true if the testPlugin is considered to be "equivalent" to the
+ * this plugin. The equivalency test is at the discretion of the plugin
+ * implementation. The PluginRegistry will use this method when starting
+ * new plugins to see if a given plugin is considered equivalent to an
+ * already running plugin with the same name. If they are considered to
+ * be equivalent, the currently running plugin will be left in place, and
+ * the new plugin will not be started.
+ * <p/>
+ * It is possible to override the equals() method, however this has
+ * more meaning than is required for this simple test and would also
+ * require the overriding of the hashCode() method as well. All of this
+ * is more work than is needed, so this simple method is used instead.
+ *
+ * @param testPlugin The plugin to test equivalency against.
+ * @return Returns true if testPlugin is considered to be equivelent.
+ */
+ boolean isEquivalent(Plugin testPlugin);
+
+ /**
+ * Call when the plugin should be stopped.
+ */
+ void shutdown();
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginEvent.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginEvent.java b/src/main/java/org/apache/log4j/plugins/PluginEvent.java
new file mode 100644
index 0000000..1843034
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginEvent.java
@@ -0,0 +1,47 @@
+/*
+ * 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.EventObject;
+
+
+/**
+ * All Plugin events are encapsulated in this class, which
+ * simply contains the source Plugin, but may in future include more
+ * information.
+ *
+ * @author Paul Smith
+ */
+public class PluginEvent extends EventObject {
+ /**
+ * @param source The source plugin of the event
+ */
+ PluginEvent(final Plugin source) {
+ super(source);
+ }
+
+ /**
+ * Returns the source Plugin of this event, which is simple
+ * the getSource() method casted to Plugin for convenience.
+ *
+ * @return Plugin source of this event
+ */
+ public Plugin getPlugin() {
+ return (Plugin) getSource();
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginListener.java b/src/main/java/org/apache/log4j/plugins/PluginListener.java
new file mode 100644
index 0000000..11f628e
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginListener.java
@@ -0,0 +1,43 @@
+/*
+ * 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.EventListener;
+
+
+/**
+ * PluginListeners are notified when plugins are started or stopped
+ * by the PluginRegistry.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ */
+public interface PluginListener extends EventListener {
+ /**
+ * Notification that plugin has started.
+ * @param e event
+ */
+ void pluginStarted(PluginEvent e);
+
+ /**
+ * Notification that plugin has stopped.
+ * @param e event
+ */
+ void pluginStopped(PluginEvent e);
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginRegistry.java b/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
new file mode 100644
index 0000000..d34f885
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
@@ -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();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java b/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
new file mode 100644
index 0000000..2660473
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
@@ -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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Receiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Receiver.java b/src/main/java/org/apache/log4j/plugins/Receiver.java
new file mode 100644
index 0000000..d78ae59
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Receiver.java
@@ -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ülcü
+ * @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);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
new file mode 100644
index 0000000..4fca465
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
@@ -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;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
new file mode 100644
index 0000000..535736c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
@@ -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;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
new file mode 100644
index 0000000..f1a4cc5
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
@@ -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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java b/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
new file mode 100644
index 0000000..368ecf9
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
@@ -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;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
new file mode 100644
index 0000000..bb40507
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
@@ -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);
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/scheduler/Job.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/scheduler/Job.java b/src/main/java/org/apache/log4j/scheduler/Job.java
new file mode 100644
index 0000000..a0e9be4
--- /dev/null
+++ b/src/main/java/org/apache/log4j/scheduler/Job.java
@@ -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ülcü
+ */
+public interface Job {
+ /**
+ * Execute job.
+ */
+ void execute();
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/scheduler/Scheduler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/scheduler/Scheduler.java b/src/main/java/org/apache/log4j/scheduler/Scheduler.java
new file mode 100644
index 0000000..72809f7
--- /dev/null
+++ b/src/main/java/org/apache/log4j/scheduler/Scheduler.java
@@ -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;
+ }
+ }
+
+}
+
+
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Component.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Component.java b/src/main/java/org/apache/log4j/spi/Component.java
new file mode 100644
index 0000000..42ef29a
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Component.java
@@ -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);
+
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/ComponentBase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/ComponentBase.java b/src/main/java/org/apache/log4j/spi/ComponentBase.java
new file mode 100644
index 0000000..78932f7
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/ComponentBase.java
@@ -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();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Decoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Decoder.java b/src/main/java/org/apache/log4j/spi/Decoder.java
new file mode 100644
index 0000000..d4686ad
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Decoder.java
@@ -0,0 +1,63 @@
+/*
+ * 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.IOException;
+
+import java.net.URL;
+
+import java.util.Map;
+import java.util.Vector;
+
+
+/**
+ * Allow LoggingEvents to be reconstructed from a different format
+ * (usually XML).
+ *
+ * @author Scott Deboy (sdeboy@apache.org)
+ */
+public interface Decoder {
+ /**
+ * Decode events from document.
+ * @param document document to decode.
+ * @return list of LoggingEvent instances.
+ */
+ Vector decodeEvents(String document);
+
+ /**
+ * Decode event from string.
+ * @param event string representation of event
+ * @return event
+ */
+ LoggingEvent decode(String event);
+
+ /**
+ * Decode event from document retreived from URL.
+ * @param url url of document
+ * @return list of LoggingEvent instances.
+ * @throws IOException if IO error resolving document.
+ */
+ Vector decode(URL url) throws IOException;
+
+ /**
+ * Sets additional properties.
+ * @param additionalProperties map of additional properties.
+ */
+ void setAdditionalProperties(Map additionalProperties);
+}
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/ErrorItem.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/ErrorItem.java b/src/main/java/org/apache/log4j/spi/ErrorItem.java
new file mode 100644
index 0000000..f6f3686
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/ErrorItem.java
@@ -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);
+ }
+ }
+}