[Git][java-team/apache-log4j1.2][buster] 10 commits: Import Debian changes 1.2.17-7
Markus Koschany (@apo)
gitlab at salsa.debian.org
Sat Feb 12 10:17:59 GMT 2022
Markus Koschany pushed to branch buster at Debian Java Maintainers / apache-log4j1.2
Commits:
5397a7a9 by Markus Koschany at 2020-05-02T16:36:11+02:00
Import Debian changes 1.2.17-7
apache-log4j1.2 (1.2.17-7) unstable; urgency=medium
* Team upload.
* Transition to bnd 2.1.0.
* Vcs-Browser: Use https.
- - - - -
a0103883 by Markus Koschany at 2020-05-02T16:38:13+02:00
Add CVE-2019-17571.patch
- - - - -
8596f85b by Markus Koschany at 2020-05-02T16:39:30+02:00
Update changelog
- - - - -
a529695e by Markus Koschany at 2022-01-31T13:16:06+01:00
Really apply the patches
- - - - -
9710d682 by Markus Koschany at 2022-01-31T13:18:33+01:00
Mitigate the impact of CVE-2022-23302 CVE-2022-23305 CVE-2022-23307
- - - - -
a21c0e08 by Markus Koschany at 2022-01-31T13:19:37+01:00
Really apply the patches
- - - - -
a8f7a6fe by Markus Koschany at 2022-01-31T13:20:05+01:00
Mitigate against CVE-2021-4104
- - - - -
4215efaf by Markus Koschany at 2022-01-31T13:28:23+01:00
Update changelog
- - - - -
feec4213 by Markus Koschany at 2022-02-12T10:39:25+01:00
Merge branch 'stretch' into buster
- - - - -
406287eb by Markus Koschany at 2022-02-12T10:43:36+01:00
Update changelog
- - - - -
6 changed files:
- debian/changelog
- + debian/patches/CVE-2021-4104.patch
- + debian/patches/CVE-2022-23302.patch
- + debian/patches/CVE-2022-23305.patch
- + debian/patches/CVE-2022-23307.patch
- debian/patches/series
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,17 @@
+apache-log4j1.2 (1.2.17-8+deb10u2) buster; urgency=medium
+
+ * Team upload.
+ * Fix CVE-2021-4104, CVE-2022-23302, CVE-2022-23305 and CVE-2022-23307.
+ Multiple security vulnerabilities have been discovered in
+ Apache Log4j 1.2 when it is configured to use JMSSink, JDBCAppender and
+ JMSAppender or Apache Chainsaw. Note that a possible attacker requires
+ write access to the Log4j configuration and the aforementioned features are
+ not enabled by default. In order to completely mitigate against these
+ vulnerabilities the related classes have been removed from the resulting
+ jar file.
+
+ -- Markus Koschany <apo at debian.org> Sat, 12 Feb 2022 10:40:19 +0100
+
apache-log4j1.2 (1.2.17-8+deb10u1) buster-security; urgency=high
* Team upload.
=====================================
debian/patches/CVE-2021-4104.patch
=====================================
@@ -0,0 +1,463 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 30 Jan 2022 22:34:52 +0100
+Subject: CVE-2021-4104
+
+Bug-Debian: https://bugs.debian.org/1004482
+
+This change mitigates the impact of CVE-2021-4104. Apache Log4j 1.2 has
+reached end of life in August 2015. No further updates will be available.
+---
+ .../java/org/apache/log4j/net/JMSAppender.java | 444 ---------------------
+ 1 file changed, 444 deletions(-)
+ delete mode 100644 src/main/java/org/apache/log4j/net/JMSAppender.java
+
+diff --git a/src/main/java/org/apache/log4j/net/JMSAppender.java b/src/main/java/org/apache/log4j/net/JMSAppender.java
+deleted file mode 100644
+index 3482702..0000000
+--- a/src/main/java/org/apache/log4j/net/JMSAppender.java
++++ /dev/null
+@@ -1,444 +0,0 @@
+-/*
+- * 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 org.apache.log4j.AppenderSkeleton;
+-import org.apache.log4j.helpers.LogLog;
+-import org.apache.log4j.spi.ErrorCode;
+-import org.apache.log4j.spi.LoggingEvent;
+-
+-import javax.jms.JMSException;
+-import javax.jms.ObjectMessage;
+-import javax.jms.Session;
+-import javax.jms.Topic;
+-import javax.jms.TopicConnection;
+-import javax.jms.TopicConnectionFactory;
+-import javax.jms.TopicPublisher;
+-import javax.jms.TopicSession;
+-import javax.naming.Context;
+-import javax.naming.InitialContext;
+-import javax.naming.NameNotFoundException;
+-import javax.naming.NamingException;
+-import java.util.Properties;
+-
+-/**
+- * A simple appender that publishes events to a JMS Topic. The events
+- * are serialized and transmitted as JMS message type {@link
+- * ObjectMessage}.
+-
+- * <p>JMS {@link Topic topics} and {@link TopicConnectionFactory topic
+- * connection factories} are administered objects that are retrieved
+- * using JNDI messaging which in turn requires the retrieval of a JNDI
+- * {@link Context}.
+-
+- * <p>There are two common methods for retrieving a JNDI {@link
+- * Context}. If a file resource named <em>jndi.properties</em> is
+- * available to the JNDI API, it will use the information found
+- * therein to retrieve an initial JNDI context. To obtain an initial
+- * context, your code will simply call:
+-
+- <pre>
+- InitialContext jndiContext = new InitialContext();
+- </pre>
+-
+- * <p>Calling the no-argument <code>InitialContext()</code> method
+- * will also work from within Enterprise Java Beans (EJBs) because it
+- * is part of the EJB contract for application servers to provide each
+- * bean an environment naming context (ENC).
+-
+- * <p>In the second approach, several predetermined properties are set
+- * and these properties are passed to the <code>InitialContext</code>
+- * constructor to connect to the naming service provider. For example,
+- * to connect to JBoss naming service one would write:
+-
+-<pre>
+- Properties env = new Properties( );
+- env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
+- env.put(Context.PROVIDER_URL, "jnp://hostname:1099");
+- env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
+- InitialContext jndiContext = new InitialContext(env);
+-</pre>
+-
+- * where <em>hostname</em> is the host where the JBoss application
+- * server is running.
+- *
+- * <p>To connect to the the naming service of Weblogic application
+- * server one would write:
+-
+-<pre>
+- Properties env = new Properties( );
+- env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
+- env.put(Context.PROVIDER_URL, "t3://localhost:7001");
+- InitialContext jndiContext = new InitialContext(env);
+-</pre>
+-
+- * <p>Other JMS providers will obviously require different values.
+- *
+- * The initial JNDI context can be obtained by calling the
+- * no-argument <code>InitialContext()</code> method in EJBs. Only
+- * clients running in a separate JVM need to be concerned about the
+- * <em>jndi.properties</em> file and calling {@link
+- * InitialContext#InitialContext()} or alternatively correctly
+- * setting the different properties before calling {@link
+- * InitialContext#InitialContext(java.util.Hashtable)} method.
+-
+-
+- @author Ceki Gülcü */
+-public class JMSAppender extends AppenderSkeleton {
+-
+- String securityPrincipalName;
+- String securityCredentials;
+- String initialContextFactoryName;
+- String urlPkgPrefixes;
+- String providerURL;
+- String topicBindingName;
+- String tcfBindingName;
+- String userName;
+- String password;
+- boolean locationInfo;
+-
+- TopicConnection topicConnection;
+- TopicSession topicSession;
+- TopicPublisher topicPublisher;
+-
+- public
+- JMSAppender() {
+- }
+-
+- /**
+- The <b>TopicConnectionFactoryBindingName</b> option takes a
+- string value. Its value will be used to lookup the appropriate
+- <code>TopicConnectionFactory</code> from the JNDI context.
+- */
+- public
+- void setTopicConnectionFactoryBindingName(String tcfBindingName) {
+- this.tcfBindingName = tcfBindingName;
+- }
+-
+- /**
+- Returns the value of the <b>TopicConnectionFactoryBindingName</b> option.
+- */
+- public
+- String getTopicConnectionFactoryBindingName() {
+- return tcfBindingName;
+- }
+-
+- /**
+- The <b>TopicBindingName</b> option takes a
+- string value. Its value will be used to lookup the appropriate
+- <code>Topic</code> from the JNDI context.
+- */
+- public
+- void setTopicBindingName(String topicBindingName) {
+- this.topicBindingName = topicBindingName;
+- }
+-
+- /**
+- Returns the value of the <b>TopicBindingName</b> option.
+- */
+- public
+- String getTopicBindingName() {
+- return topicBindingName;
+- }
+-
+-
+- /**
+- Returns value of the <b>LocationInfo</b> property which
+- determines whether location (stack) info is sent to the remote
+- subscriber. */
+- public
+- boolean getLocationInfo() {
+- return locationInfo;
+- }
+-
+- /**
+- * Options are activated and become effective only after calling
+- * this method.*/
+- public void activateOptions() {
+- TopicConnectionFactory topicConnectionFactory;
+-
+- try {
+- Context jndi;
+-
+- LogLog.debug("Getting initial context.");
+- if(initialContextFactoryName != null) {
+- Properties env = new Properties( );
+- env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName);
+- if(providerURL != null) {
+- env.put(Context.PROVIDER_URL, providerURL);
+- } else {
+- LogLog.warn("You have set InitialContextFactoryName option but not the "
+- +"ProviderURL. This is likely to cause problems.");
+- }
+- if(urlPkgPrefixes != null) {
+- env.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes);
+- }
+-
+- if(securityPrincipalName != null) {
+- env.put(Context.SECURITY_PRINCIPAL, securityPrincipalName);
+- if(securityCredentials != null) {
+- env.put(Context.SECURITY_CREDENTIALS, securityCredentials);
+- } else {
+- LogLog.warn("You have set SecurityPrincipalName option but not the "
+- +"SecurityCredentials. This is likely to cause problems.");
+- }
+- }
+- jndi = new InitialContext(env);
+- } else {
+- jndi = new InitialContext();
+- }
+-
+- LogLog.debug("Looking up ["+tcfBindingName+"]");
+- topicConnectionFactory = (TopicConnectionFactory) lookup(jndi, tcfBindingName);
+- LogLog.debug("About to create TopicConnection.");
+- if(userName != null) {
+- topicConnection = topicConnectionFactory.createTopicConnection(userName,
+- password);
+- } else {
+- topicConnection = topicConnectionFactory.createTopicConnection();
+- }
+-
+- LogLog.debug("Creating TopicSession, non-transactional, "
+- +"in AUTO_ACKNOWLEDGE mode.");
+- topicSession = topicConnection.createTopicSession(false,
+- Session.AUTO_ACKNOWLEDGE);
+-
+- LogLog.debug("Looking up topic name ["+topicBindingName+"].");
+- Topic topic = (Topic) lookup(jndi, topicBindingName);
+-
+- LogLog.debug("Creating TopicPublisher.");
+- topicPublisher = topicSession.createPublisher(topic);
+-
+- LogLog.debug("Starting TopicConnection.");
+- topicConnection.start();
+-
+- jndi.close();
+- } catch(JMSException e) {
+- errorHandler.error("Error while activating options for appender named ["+name+
+- "].", e, ErrorCode.GENERIC_FAILURE);
+- } catch(NamingException e) {
+- errorHandler.error("Error while activating options for appender named ["+name+
+- "].", e, ErrorCode.GENERIC_FAILURE);
+- } catch(RuntimeException e) {
+- errorHandler.error("Error while activating options for appender named ["+name+
+- "].", e, ErrorCode.GENERIC_FAILURE);
+- }
+- }
+-
+- protected Object lookup(Context ctx, String name) throws NamingException {
+- try {
+- return ctx.lookup(name);
+- } catch(NameNotFoundException e) {
+- LogLog.error("Could not find name ["+name+"].");
+- throw e;
+- }
+- }
+-
+- protected boolean checkEntryConditions() {
+- String fail = null;
+-
+- if(this.topicConnection == null) {
+- fail = "No TopicConnection";
+- } else if(this.topicSession == null) {
+- fail = "No TopicSession";
+- } else if(this.topicPublisher == null) {
+- fail = "No TopicPublisher";
+- }
+-
+- if(fail != null) {
+- errorHandler.error(fail +" for JMSAppender named ["+name+"].");
+- return false;
+- } else {
+- return true;
+- }
+- }
+-
+- /**
+- Close this JMSAppender. Closing releases all resources used by the
+- appender. A closed appender cannot be re-opened. */
+- public synchronized void close() {
+- // The synchronized modifier avoids concurrent append and close operations
+-
+- if(this.closed)
+- return;
+-
+- LogLog.debug("Closing appender ["+name+"].");
+- this.closed = true;
+-
+- try {
+- if(topicSession != null)
+- topicSession.close();
+- if(topicConnection != null)
+- topicConnection.close();
+- } catch(JMSException e) {
+- LogLog.error("Error while closing JMSAppender ["+name+"].", e);
+- } catch(RuntimeException e) {
+- LogLog.error("Error while closing JMSAppender ["+name+"].", e);
+- }
+- // Help garbage collection
+- topicPublisher = null;
+- topicSession = null;
+- topicConnection = null;
+- }
+-
+- /**
+- This method called by {@link AppenderSkeleton#doAppend} method to
+- do most of the real appending work. */
+- public void append(LoggingEvent event) {
+- if(!checkEntryConditions()) {
+- return;
+- }
+-
+- try {
+- ObjectMessage msg = topicSession.createObjectMessage();
+- if(locationInfo) {
+- event.getLocationInformation();
+- }
+- msg.setObject(event);
+- topicPublisher.publish(msg);
+- } catch(JMSException e) {
+- errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
+- ErrorCode.GENERIC_FAILURE);
+- } catch(RuntimeException e) {
+- errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
+- ErrorCode.GENERIC_FAILURE);
+- }
+- }
+-
+- /**
+- * Returns the value of the <b>InitialContextFactoryName</b> option.
+- * See {@link #setInitialContextFactoryName} for more details on the
+- * meaning of this option.
+- * */
+- public String getInitialContextFactoryName() {
+- return initialContextFactoryName;
+- }
+-
+- /**
+- * Setting the <b>InitialContextFactoryName</b> method will cause
+- * this <code>JMSAppender</code> instance to use the {@link
+- * InitialContext#InitialContext(Hashtable)} method instead of the
+- * no-argument constructor. If you set this option, you should also
+- * at least set the <b>ProviderURL</b> option.
+- *
+- * <p>See also {@link #setProviderURL(String)}.
+- * */
+- public void setInitialContextFactoryName(String initialContextFactoryName) {
+- this.initialContextFactoryName = initialContextFactoryName;
+- }
+-
+- public String getProviderURL() {
+- return providerURL;
+- }
+-
+- public void setProviderURL(String providerURL) {
+- this.providerURL = providerURL;
+- }
+-
+- String getURLPkgPrefixes( ) {
+- return urlPkgPrefixes;
+- }
+-
+- public void setURLPkgPrefixes(String urlPkgPrefixes ) {
+- this.urlPkgPrefixes = urlPkgPrefixes;
+- }
+-
+- public String getSecurityCredentials() {
+- return securityCredentials;
+- }
+-
+- public void setSecurityCredentials(String securityCredentials) {
+- this.securityCredentials = securityCredentials;
+- }
+-
+-
+- public String getSecurityPrincipalName() {
+- return securityPrincipalName;
+- }
+-
+- public void setSecurityPrincipalName(String securityPrincipalName) {
+- this.securityPrincipalName = securityPrincipalName;
+- }
+-
+- public String getUserName() {
+- return userName;
+- }
+-
+- /**
+- * The user name to use when {@link
+- * TopicConnectionFactory#createTopicConnection(String, String)
+- * creating a topic session}. If you set this option, you should
+- * also set the <b>Password</b> option. See {@link
+- * #setPassword(String)}.
+- * */
+- public void setUserName(String userName) {
+- this.userName = userName;
+- }
+-
+- public String getPassword() {
+- return password;
+- }
+-
+- /**
+- * The paswword to use when creating a topic session.
+- */
+- public void setPassword(String password) {
+- this.password = password;
+- }
+-
+-
+- /**
+- If true, the information sent to the remote subscriber will
+- include caller's location information. By default no location
+- information is sent to the subscriber. */
+- public void setLocationInfo(boolean locationInfo) {
+- this.locationInfo = locationInfo;
+- }
+-
+- /**
+- * Returns the TopicConnection used for this appender. Only valid after
+- * activateOptions() method has been invoked.
+- */
+- protected TopicConnection getTopicConnection() {
+- return topicConnection;
+- }
+-
+- /**
+- * Returns the TopicSession used for this appender. Only valid after
+- * activateOptions() method has been invoked.
+- */
+- protected TopicSession getTopicSession() {
+- return topicSession;
+- }
+-
+- /**
+- * Returns the TopicPublisher used for this appender. Only valid after
+- * activateOptions() method has been invoked.
+- */
+- protected TopicPublisher getTopicPublisher() {
+- return topicPublisher;
+- }
+-
+- /**
+- * The JMSAppender sends serialized events and consequently does not
+- * require a layout.
+- */
+- public boolean requiresLayout() {
+- return false;
+- }
+-}
=====================================
debian/patches/CVE-2022-23302.patch
=====================================
@@ -0,0 +1,172 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 30 Jan 2022 22:16:04 +0100
+Subject: CVE-2022-23302
+
+Bug-Debian: https://bugs.debian.org/1004482
+
+This change mitigates the impact of CVE-2022-23302. Apache Log4j 1.2 has
+reached end of life in August 2015. No further updates will be available.
+---
+ src/main/java/org/apache/log4j/net/JMSSink.java | 153 ------------------------
+ 1 file changed, 153 deletions(-)
+ delete mode 100644 src/main/java/org/apache/log4j/net/JMSSink.java
+
+diff --git a/src/main/java/org/apache/log4j/net/JMSSink.java b/src/main/java/org/apache/log4j/net/JMSSink.java
+deleted file mode 100644
+index 6a02831..0000000
+--- a/src/main/java/org/apache/log4j/net/JMSSink.java
++++ /dev/null
+@@ -1,153 +0,0 @@
+-/*
+- * 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 org.apache.log4j.Logger;
+-import org.apache.log4j.PropertyConfigurator;
+-import org.apache.log4j.spi.LoggingEvent;
+-import org.apache.log4j.xml.DOMConfigurator;
+-
+-import javax.jms.JMSException;
+-import javax.jms.ObjectMessage;
+-import javax.jms.Session;
+-import javax.jms.Topic;
+-import javax.jms.TopicConnection;
+-import javax.jms.TopicConnectionFactory;
+-import javax.jms.TopicSession;
+-import javax.jms.TopicSubscriber;
+-import javax.naming.Context;
+-import javax.naming.InitialContext;
+-import javax.naming.NameNotFoundException;
+-import javax.naming.NamingException;
+-import java.io.BufferedReader;
+-import java.io.InputStreamReader;
+-
+-/**
+- * A simple application that consumes logging events sent by a {@link
+- * JMSAppender}.
+- *
+- *
+- * @author Ceki Gülcü
+- * */
+-public class JMSSink implements javax.jms.MessageListener {
+-
+- static Logger logger = Logger.getLogger(JMSSink.class);
+-
+- static public void main(String[] args) throws Exception {
+- if(args.length != 5) {
+- usage("Wrong number of arguments.");
+- }
+-
+- String tcfBindingName = args[0];
+- String topicBindingName = args[1];
+- String username = args[2];
+- String password = args[3];
+-
+-
+- String configFile = args[4];
+-
+- if(configFile.endsWith(".xml")) {
+- DOMConfigurator.configure(configFile);
+- } else {
+- PropertyConfigurator.configure(configFile);
+- }
+-
+- new JMSSink(tcfBindingName, topicBindingName, username, password);
+-
+- BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+- // Loop until the word "exit" is typed
+- System.out.println("Type \"exit\" to quit JMSSink.");
+- while(true){
+- String s = stdin.readLine( );
+- if (s.equalsIgnoreCase("exit")) {
+- System.out.println("Exiting. Kill the application if it does not exit "
+- + "due to daemon threads.");
+- return;
+- }
+- }
+- }
+-
+- public JMSSink( String tcfBindingName, String topicBindingName, String username,
+- String password) {
+-
+- try {
+- Context ctx = new InitialContext();
+- TopicConnectionFactory topicConnectionFactory;
+- topicConnectionFactory = (TopicConnectionFactory) lookup(ctx,
+- tcfBindingName);
+-
+- TopicConnection topicConnection =
+- topicConnectionFactory.createTopicConnection(username,
+- password);
+- topicConnection.start();
+-
+- TopicSession topicSession = topicConnection.createTopicSession(false,
+- Session.AUTO_ACKNOWLEDGE);
+-
+- Topic topic = (Topic)ctx.lookup(topicBindingName);
+-
+- TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
+-
+- topicSubscriber.setMessageListener(this);
+-
+- } catch(JMSException e) {
+- logger.error("Could not read JMS message.", e);
+- } catch(NamingException e) {
+- logger.error("Could not read JMS message.", e);
+- } catch(RuntimeException e) {
+- logger.error("Could not read JMS message.", e);
+- }
+- }
+-
+- public void onMessage(javax.jms.Message message) {
+- LoggingEvent event;
+- Logger remoteLogger;
+-
+- try {
+- if(message instanceof ObjectMessage) {
+- ObjectMessage objectMessage = (ObjectMessage) message;
+- event = (LoggingEvent) objectMessage.getObject();
+- remoteLogger = Logger.getLogger(event.getLoggerName());
+- remoteLogger.callAppenders(event);
+- } else {
+- logger.warn("Received message is of type "+message.getJMSType()
+- +", was expecting ObjectMessage.");
+- }
+- } catch(JMSException jmse) {
+- logger.error("Exception thrown while processing incoming message.",
+- jmse);
+- }
+- }
+-
+-
+- protected static Object lookup(Context ctx, String name) throws NamingException {
+- try {
+- return ctx.lookup(name);
+- } catch(NameNotFoundException e) {
+- logger.error("Could not find name ["+name+"].");
+- throw e;
+- }
+- }
+-
+- static void usage(String msg) {
+- System.err.println(msg);
+- System.err.println("Usage: java " + JMSSink.class.getName()
+- + " TopicConnectionFactoryBindingName TopicBindingName username password configFile");
+- System.exit(1);
+- }
+-}
=====================================
debian/patches/CVE-2022-23305.patch
=====================================
@@ -0,0 +1,417 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 30 Jan 2022 22:18:18 +0100
+Subject: CVE-2022-23305
+
+Bug-Debian: https://bugs.debian.org/1004482
+
+This change mitigates the impact of CVE-2022-23305. Apache Log4j 1.2 has
+reached end of life in August 2015. No further updates will be available.
+---
+ .../java/org/apache/log4j/jdbc/JDBCAppender.java | 398 ---------------------
+ 1 file changed, 398 deletions(-)
+ delete mode 100644 src/main/java/org/apache/log4j/jdbc/JDBCAppender.java
+
+diff --git a/src/main/java/org/apache/log4j/jdbc/JDBCAppender.java b/src/main/java/org/apache/log4j/jdbc/JDBCAppender.java
+deleted file mode 100644
+index ad35f65..0000000
+--- a/src/main/java/org/apache/log4j/jdbc/JDBCAppender.java
++++ /dev/null
+@@ -1,398 +0,0 @@
+-/*
+- * 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.jdbc;
+-
+-import java.sql.Connection;
+-import java.sql.DriverManager;
+-import java.sql.SQLException;
+-import java.sql.Statement;
+-import java.util.ArrayList;
+-import java.util.Iterator;
+-
+-import org.apache.log4j.PatternLayout;
+-import org.apache.log4j.spi.ErrorCode;
+-import org.apache.log4j.spi.LoggingEvent;
+-
+-
+-/**
+- The JDBCAppender provides for sending log events to a database.
+-
+- <p><b><font color="#FF2222">WARNING: This version of JDBCAppender
+- is very likely to be completely replaced in the future. Moreoever,
+- it does not log exceptions</font></b>.
+-
+- <p>Each append call adds to an <code>ArrayList</code> buffer. When
+- the buffer is filled each log event is placed in a sql statement
+- (configurable) and executed.
+-
+- <b>BufferSize</b>, <b>db URL</b>, <b>User</b>, & <b>Password</b> are
+- configurable options in the standard log4j ways.
+-
+- <p>The <code>setSql(String sql)</code> sets the SQL statement to be
+- used for logging -- this statement is sent to a
+- <code>PatternLayout</code> (either created automaticly by the
+- appender or added by the user). Therefore by default all the
+- conversion patterns in <code>PatternLayout</code> can be used
+- inside of the statement. (see the test cases for examples)
+-
+- <p>Overriding the {@link #getLogStatement} method allows more
+- explicit control of the statement used for logging.
+-
+- <p>For use as a base class:
+-
+- <ul>
+-
+- <li>Override <code>getConnection()</code> to pass any connection
+- you want. Typically this is used to enable application wide
+- connection pooling.
+-
+- <li>Override <code>closeConnection(Connection con)</code> -- if
+- you override getConnection make sure to implement
+- <code>closeConnection</code> to handle the connection you
+- generated. Typically this would return the connection to the
+- pool it came from.
+-
+- <li>Override <code>getLogStatement(LoggingEvent event)</code> to
+- produce specialized or dynamic statements. The default uses the
+- sql option value.
+-
+- </ul>
+-
+- @author Kevin Steppe (<A HREF="mailto:ksteppe at pacbell.net">ksteppe at pacbell.net</A>)
+-
+-*/
+-public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
+- implements org.apache.log4j.Appender {
+-
+- /**
+- * URL of the DB for default connection handling
+- */
+- protected String databaseURL = "jdbc:odbc:myDB";
+-
+- /**
+- * User to connect as for default connection handling
+- */
+- protected String databaseUser = "me";
+-
+- /**
+- * User to use for default connection handling
+- */
+- protected String databasePassword = "mypassword";
+-
+- /**
+- * Connection used by default. The connection is opened the first time it
+- * is needed and then held open until the appender is closed (usually at
+- * garbage collection). This behavior is best modified by creating a
+- * sub-class and overriding the <code>getConnection</code> and
+- * <code>closeConnection</code> methods.
+- */
+- protected Connection connection = null;
+-
+- /**
+- * Stores the string given to the pattern layout for conversion into a SQL
+- * statement, eg: insert into LogTable (Thread, Class, Message) values
+- * ("%t", "%c", "%m").
+- *
+- * Be careful of quotes in your messages!
+- *
+- * Also see PatternLayout.
+- */
+- protected String sqlStatement = "";
+-
+- /**
+- * size of LoggingEvent buffer before writting to the database.
+- * Default is 1.
+- */
+- protected int bufferSize = 1;
+-
+- /**
+- * ArrayList holding the buffer of Logging Events.
+- */
+- protected ArrayList buffer;
+-
+- /**
+- * Helper object for clearing out the buffer
+- */
+- protected ArrayList removes;
+-
+- private boolean locationInfo = false;
+-
+- public JDBCAppender() {
+- super();
+- buffer = new ArrayList(bufferSize);
+- removes = new ArrayList(bufferSize);
+- }
+-
+- /**
+- * Gets whether the location of the logging request call
+- * should be captured.
+- *
+- * @since 1.2.16
+- * @return the current value of the <b>LocationInfo</b> option.
+- */
+- public boolean getLocationInfo() {
+- return locationInfo;
+- }
+-
+- /**
+- * The <b>LocationInfo</b> option takes a boolean value. By default, it is
+- * set to false which means there will be no effort to extract the location
+- * information related to the event. As a result, the event that will be
+- * ultimately logged will likely to contain the wrong location information
+- * (if present in the log format).
+- * <p/>
+- * <p/>
+- * Location information extraction is comparatively very slow and should be
+- * avoided unless performance is not a concern.
+- * </p>
+- * @since 1.2.16
+- * @param flag true if location information should be extracted.
+- */
+- public void setLocationInfo(final boolean flag) {
+- locationInfo = flag;
+- }
+-
+-
+- /**
+- * Adds the event to the buffer. When full the buffer is flushed.
+- */
+- public void append(LoggingEvent event) {
+- event.getNDC();
+- event.getThreadName();
+- // Get a copy of this thread's MDC.
+- event.getMDCCopy();
+- if (locationInfo) {
+- event.getLocationInformation();
+- }
+- event.getRenderedMessage();
+- event.getThrowableStrRep();
+- buffer.add(event);
+-
+- if (buffer.size() >= bufferSize)
+- flushBuffer();
+- }
+-
+- /**
+- * By default getLogStatement sends the event to the required Layout object.
+- * The layout will format the given pattern into a workable SQL string.
+- *
+- * Overriding this provides direct access to the LoggingEvent
+- * when constructing the logging statement.
+- *
+- */
+- protected String getLogStatement(LoggingEvent event) {
+- return getLayout().format(event);
+- }
+-
+- /**
+- *
+- * Override this to provide an alertnate method of getting
+- * connections (such as caching). One method to fix this is to open
+- * connections at the start of flushBuffer() and close them at the
+- * end. I use a connection pool outside of JDBCAppender which is
+- * accessed in an override of this method.
+- * */
+- protected void execute(String sql) throws SQLException {
+-
+- Connection con = null;
+- Statement stmt = null;
+-
+- try {
+- con = getConnection();
+-
+- stmt = con.createStatement();
+- stmt.executeUpdate(sql);
+- } finally {
+- if(stmt != null) {
+- stmt.close();
+- }
+- closeConnection(con);
+- }
+-
+- //System.out.println("Execute: " + sql);
+- }
+-
+-
+- /**
+- * Override this to return the connection to a pool, or to clean up the
+- * resource.
+- *
+- * The default behavior holds a single connection open until the appender
+- * is closed (typically when garbage collected).
+- */
+- protected void closeConnection(Connection con) {
+- }
+-
+- /**
+- * Override this to link with your connection pooling system.
+- *
+- * By default this creates a single connection which is held open
+- * until the object is garbage collected.
+- */
+- protected Connection getConnection() throws SQLException {
+- if (!DriverManager.getDrivers().hasMoreElements())
+- setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
+-
+- if (connection == null) {
+- connection = DriverManager.getConnection(databaseURL, databaseUser,
+- databasePassword);
+- }
+-
+- return connection;
+- }
+-
+- /**
+- * Closes the appender, flushing the buffer first then closing the default
+- * connection if it is open.
+- */
+- public void close()
+- {
+- flushBuffer();
+-
+- try {
+- if (connection != null && !connection.isClosed())
+- connection.close();
+- } catch (SQLException e) {
+- errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
+- }
+- this.closed = true;
+- }
+-
+- /**
+- * loops through the buffer of LoggingEvents, gets a
+- * sql string from getLogStatement() and sends it to execute().
+- * Errors are sent to the errorHandler.
+- *
+- * If a statement fails the LoggingEvent stays in the buffer!
+- */
+- public void flushBuffer() {
+- //Do the actual logging
+- removes.ensureCapacity(buffer.size());
+- for (Iterator i = buffer.iterator(); i.hasNext();) {
+- LoggingEvent logEvent = (LoggingEvent)i.next();
+- try {
+- String sql = getLogStatement(logEvent);
+- execute(sql);
+- }
+- catch (SQLException e) {
+- errorHandler.error("Failed to excute sql", e,
+- ErrorCode.FLUSH_FAILURE);
+- } finally {
+- removes.add(logEvent);
+- }
+- }
+-
+- // remove from the buffer any events that were reported
+- buffer.removeAll(removes);
+-
+- // clear the buffer of reported events
+- removes.clear();
+- }
+-
+-
+- /** closes the appender before disposal */
+- public void finalize() {
+- close();
+- }
+-
+-
+- /**
+- * JDBCAppender requires a layout.
+- * */
+- public boolean requiresLayout() {
+- return true;
+- }
+-
+-
+- /**
+- *
+- */
+- public void setSql(String s) {
+- sqlStatement = s;
+- if (getLayout() == null) {
+- this.setLayout(new PatternLayout(s));
+- }
+- else {
+- ((PatternLayout)getLayout()).setConversionPattern(s);
+- }
+- }
+-
+-
+- /**
+- * Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
+- */
+- public String getSql() {
+- return sqlStatement;
+- }
+-
+-
+- public void setUser(String user) {
+- databaseUser = user;
+- }
+-
+-
+- public void setURL(String url) {
+- databaseURL = url;
+- }
+-
+-
+- public void setPassword(String password) {
+- databasePassword = password;
+- }
+-
+-
+- public void setBufferSize(int newBufferSize) {
+- bufferSize = newBufferSize;
+- buffer.ensureCapacity(bufferSize);
+- removes.ensureCapacity(bufferSize);
+- }
+-
+-
+- public String getUser() {
+- return databaseUser;
+- }
+-
+-
+- public String getURL() {
+- return databaseURL;
+- }
+-
+-
+- public String getPassword() {
+- return databasePassword;
+- }
+-
+-
+- public int getBufferSize() {
+- return bufferSize;
+- }
+-
+-
+- /**
+- * Ensures that the given driver class has been loaded for sql connection
+- * creation.
+- */
+- public void setDriver(String driverClass) {
+- try {
+- Class.forName(driverClass);
+- } catch (Exception e) {
+- errorHandler.error("Failed to load driver", e,
+- ErrorCode.GENERIC_FAILURE);
+- }
+- }
+-}
+-
=====================================
debian/patches/CVE-2022-23307.patch
=====================================
@@ -0,0 +1,1797 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 30 Jan 2022 22:23:12 +0100
+Subject: CVE-2022-23307
+
+Bug-Debian: https://bugs.debian.org/1004482
+
+This change mitigates the impact of CVE-2022-23307. Apache Log4j 1.2 has
+reached end of life in August 2015. No further updates will be available.
+---
+ .../org/apache/log4j/chainsaw/ControlPanel.java | 222 ------------
+ .../org/apache/log4j/chainsaw/DetailPanel.java | 170 ---------
+ .../org/apache/log4j/chainsaw/EventDetails.java | 135 -------
+ .../java/org/apache/log4j/chainsaw/ExitAction.java | 48 ---
+ .../org/apache/log4j/chainsaw/LoadXMLAction.java | 139 --------
+ .../org/apache/log4j/chainsaw/LoggingReceiver.java | 121 -------
+ src/main/java/org/apache/log4j/chainsaw/Main.java | 192 ----------
+ .../org/apache/log4j/chainsaw/MyTableModel.java | 390 ---------------------
+ .../org/apache/log4j/chainsaw/XMLFileHandler.java | 170 ---------
+ .../java/org/apache/log4j/chainsaw/package.html | 118 -------
+ 10 files changed, 1705 deletions(-)
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/ControlPanel.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/DetailPanel.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/EventDetails.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/ExitAction.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/LoadXMLAction.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/Main.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
+ delete mode 100644 src/main/java/org/apache/log4j/chainsaw/package.html
+
+diff --git a/src/main/java/org/apache/log4j/chainsaw/ControlPanel.java b/src/main/java/org/apache/log4j/chainsaw/ControlPanel.java
+deleted file mode 100644
+index 53b0b1b..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/ControlPanel.java
++++ /dev/null
+@@ -1,222 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.awt.GridBagConstraints;
+-import java.awt.GridBagLayout;
+-import java.awt.event.ActionEvent;
+-import java.awt.event.ActionListener;
+-import javax.swing.BorderFactory;
+-import javax.swing.JButton;
+-import javax.swing.JComboBox;
+-import javax.swing.JLabel;
+-import javax.swing.JPanel;
+-import javax.swing.JTextField;
+-import javax.swing.event.DocumentEvent;
+-import javax.swing.event.DocumentListener;
+-import org.apache.log4j.Logger;
+-import org.apache.log4j.Priority;
+-import org.apache.log4j.Level;
+-
+-/**
+- * Represents the controls for filtering, pausing, exiting, etc.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+-class ControlPanel extends JPanel {
+- /** use the log messages **/
+- private static final Logger LOG =
+- Logger.getLogger(ControlPanel.class);
+-
+- /**
+- * Creates a new <code>ControlPanel</code> instance.
+- *
+- * @param aModel the model to control
+- */
+- ControlPanel(final MyTableModel aModel) {
+- setBorder(BorderFactory.createTitledBorder("Controls: "));
+- final GridBagLayout gridbag = new GridBagLayout();
+- final GridBagConstraints c = new GridBagConstraints();
+- setLayout(gridbag);
+-
+- // Pad everything
+- c.ipadx = 5;
+- c.ipady = 5;
+-
+- // Add the 1st column of labels
+- c.gridx = 0;
+- c.anchor = GridBagConstraints.EAST;
+-
+- c.gridy = 0;
+- JLabel label = new JLabel("Filter Level:");
+- gridbag.setConstraints(label, c);
+- add(label);
+-
+- c.gridy++;
+- label = new JLabel("Filter Thread:");
+- gridbag.setConstraints(label, c);
+- add(label);
+-
+- c.gridy++;
+- label = new JLabel("Filter Logger:");
+- gridbag.setConstraints(label, c);
+- add(label);
+-
+- c.gridy++;
+- label = new JLabel("Filter NDC:");
+- gridbag.setConstraints(label, c);
+- add(label);
+-
+- c.gridy++;
+- label = new JLabel("Filter Message:");
+- gridbag.setConstraints(label, c);
+- add(label);
+-
+- // Add the 2nd column of filters
+- c.weightx = 1;
+- //c.weighty = 1;
+- c.gridx = 1;
+- c.anchor = GridBagConstraints.WEST;
+-
+- c.gridy = 0;
+- final Level[] allPriorities = new Level[] {Level.FATAL,
+- Level.ERROR,
+- Level.WARN,
+- Level.INFO,
+- Level.DEBUG,
+- Level.TRACE };
+-
+- final JComboBox priorities = new JComboBox(allPriorities);
+- final Level lowest = allPriorities[allPriorities.length - 1];
+- priorities.setSelectedItem(lowest);
+- aModel.setPriorityFilter(lowest);
+- gridbag.setConstraints(priorities, c);
+- add(priorities);
+- priorities.setEditable(false);
+- priorities.addActionListener(new ActionListener() {
+- public void actionPerformed(ActionEvent aEvent) {
+- aModel.setPriorityFilter(
+- (Priority) priorities.getSelectedItem());
+- }
+- });
+-
+-
+- c.fill = GridBagConstraints.HORIZONTAL;
+- c.gridy++;
+- final JTextField threadField = new JTextField("");
+- threadField.getDocument().addDocumentListener(new DocumentListener () {
+- public void insertUpdate(DocumentEvent aEvent) {
+- aModel.setThreadFilter(threadField.getText());
+- }
+- public void removeUpdate(DocumentEvent aEvente) {
+- aModel.setThreadFilter(threadField.getText());
+- }
+- public void changedUpdate(DocumentEvent aEvent) {
+- aModel.setThreadFilter(threadField.getText());
+- }
+- });
+- gridbag.setConstraints(threadField, c);
+- add(threadField);
+-
+- c.gridy++;
+- final JTextField catField = new JTextField("");
+- catField.getDocument().addDocumentListener(new DocumentListener () {
+- public void insertUpdate(DocumentEvent aEvent) {
+- aModel.setCategoryFilter(catField.getText());
+- }
+- public void removeUpdate(DocumentEvent aEvent) {
+- aModel.setCategoryFilter(catField.getText());
+- }
+- public void changedUpdate(DocumentEvent aEvent) {
+- aModel.setCategoryFilter(catField.getText());
+- }
+- });
+- gridbag.setConstraints(catField, c);
+- add(catField);
+-
+- c.gridy++;
+- final JTextField ndcField = new JTextField("");
+- ndcField.getDocument().addDocumentListener(new DocumentListener () {
+- public void insertUpdate(DocumentEvent aEvent) {
+- aModel.setNDCFilter(ndcField.getText());
+- }
+- public void removeUpdate(DocumentEvent aEvent) {
+- aModel.setNDCFilter(ndcField.getText());
+- }
+- public void changedUpdate(DocumentEvent aEvent) {
+- aModel.setNDCFilter(ndcField.getText());
+- }
+- });
+- gridbag.setConstraints(ndcField, c);
+- add(ndcField);
+-
+- c.gridy++;
+- final JTextField msgField = new JTextField("");
+- msgField.getDocument().addDocumentListener(new DocumentListener () {
+- public void insertUpdate(DocumentEvent aEvent) {
+- aModel.setMessageFilter(msgField.getText());
+- }
+- public void removeUpdate(DocumentEvent aEvent) {
+- aModel.setMessageFilter(msgField.getText());
+- }
+- public void changedUpdate(DocumentEvent aEvent) {
+- aModel.setMessageFilter(msgField.getText());
+- }
+- });
+-
+-
+- gridbag.setConstraints(msgField, c);
+- add(msgField);
+-
+- // Add the 3rd column of buttons
+- c.weightx = 0;
+- c.fill = GridBagConstraints.HORIZONTAL;
+- c.anchor = GridBagConstraints.EAST;
+- c.gridx = 2;
+-
+- c.gridy = 0;
+- final JButton exitButton = new JButton("Exit");
+- exitButton.setMnemonic('x');
+- exitButton.addActionListener(ExitAction.INSTANCE);
+- gridbag.setConstraints(exitButton, c);
+- add(exitButton);
+-
+- c.gridy++;
+- final JButton clearButton = new JButton("Clear");
+- clearButton.setMnemonic('c');
+- clearButton.addActionListener(new ActionListener() {
+- public void actionPerformed(ActionEvent aEvent) {
+- aModel.clear();
+- }
+- });
+- gridbag.setConstraints(clearButton, c);
+- add(clearButton);
+-
+- c.gridy++;
+- final JButton toggleButton = new JButton("Pause");
+- toggleButton.setMnemonic('p');
+- toggleButton.addActionListener(new ActionListener() {
+- public void actionPerformed(ActionEvent aEvent) {
+- aModel.toggle();
+- toggleButton.setText(
+- aModel.isPaused() ? "Resume" : "Pause");
+- }
+- });
+- gridbag.setConstraints(toggleButton, c);
+- add(toggleButton);
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/DetailPanel.java b/src/main/java/org/apache/log4j/chainsaw/DetailPanel.java
+deleted file mode 100644
+index 1f5dfe2..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/DetailPanel.java
++++ /dev/null
+@@ -1,170 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.awt.BorderLayout;
+-import java.text.MessageFormat;
+-import java.util.Date;
+-import javax.swing.BorderFactory;
+-import javax.swing.JEditorPane;
+-import javax.swing.JPanel;
+-import javax.swing.JScrollPane;
+-import javax.swing.JTable;
+-import javax.swing.ListSelectionModel;
+-import javax.swing.event.ListSelectionEvent;
+-import javax.swing.event.ListSelectionListener;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * A panel for showing a stack trace.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+-class DetailPanel
+- extends JPanel
+- implements ListSelectionListener
+-{
+- /** used to log events **/
+- private static final Logger LOG =
+- Logger.getLogger(DetailPanel.class);
+-
+- /** used to format the logging event **/
+- private static final MessageFormat FORMATTER = new MessageFormat(
+- "<b>Time:</b> <code>{0,time,medium}</code>" +
+- " <b>Priority:</b> <code>{1}</code>" +
+- " <b>Thread:</b> <code>{2}</code>" +
+- " <b>NDC:</b> <code>{3}</code>" +
+- "<br><b>Logger:</b> <code>{4}</code>" +
+- "<br><b>Location:</b> <code>{5}</code>" +
+- "<br><b>Message:</b>" +
+- "<pre>{6}</pre>" +
+- "<b>Throwable:</b>" +
+- "<pre>{7}</pre>");
+-
+- /** the model for the data to render **/
+- private final MyTableModel mModel;
+- /** pane for rendering detail **/
+- private final JEditorPane mDetails;
+-
+- /**
+- * Creates a new <code>DetailPanel</code> instance.
+- *
+- * @param aTable the table to listen for selections on
+- * @param aModel the model backing the table
+- */
+- DetailPanel(JTable aTable, final MyTableModel aModel) {
+- mModel = aModel;
+- setLayout(new BorderLayout());
+- setBorder(BorderFactory.createTitledBorder("Details: "));
+-
+- mDetails = new JEditorPane();
+- mDetails.setEditable(false);
+- mDetails.setContentType("text/html");
+- add(new JScrollPane(mDetails), BorderLayout.CENTER);
+-
+- final ListSelectionModel rowSM = aTable.getSelectionModel();
+- rowSM.addListSelectionListener(this);
+- }
+-
+- /** @see ListSelectionListener **/
+- public void valueChanged(ListSelectionEvent aEvent) {
+- //Ignore extra messages.
+- if (aEvent.getValueIsAdjusting()) {
+- return;
+- }
+-
+- final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
+- if (lsm.isSelectionEmpty()) {
+- mDetails.setText("Nothing selected");
+- } else {
+- final int selectedRow = lsm.getMinSelectionIndex();
+- final EventDetails e = mModel.getEventDetails(selectedRow);
+- final Object[] args =
+- {
+- new Date(e.getTimeStamp()),
+- e.getPriority(),
+- escape(e.getThreadName()),
+- escape(e.getNDC()),
+- escape(e.getCategoryName()),
+- escape(e.getLocationDetails()),
+- escape(e.getMessage()),
+- escape(getThrowableStrRep(e))
+- };
+- mDetails.setText(FORMATTER.format(args));
+- mDetails.setCaretPosition(0);
+- }
+- }
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // Private methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+- /**
+- * Returns a string representation of a throwable.
+- *
+- * @param aEvent contains the throwable information
+- * @return a <code>String</code> value
+- */
+- private static String getThrowableStrRep(EventDetails aEvent) {
+- final String[] strs = aEvent.getThrowableStrRep();
+- if (strs == null) {
+- return null;
+- }
+-
+- final StringBuffer sb = new StringBuffer();
+- for (int i = 0; i < strs.length; i++) {
+- sb.append(strs[i]).append("\n");
+- }
+-
+- return sb.toString();
+- }
+-
+- /**
+- * Escape <, > & and " as their entities. It is very
+- * dumb about & handling.
+- * @param aStr the String to escape.
+- * @return the escaped String
+- */
+- private String escape(String aStr) {
+- if (aStr == null) {
+- return null;
+- }
+-
+- final StringBuffer buf = new StringBuffer();
+- for (int i = 0; i < aStr.length(); i++) {
+- char c = aStr.charAt(i);
+- switch (c) {
+- case '<':
+- buf.append("<");
+- break;
+- case '>':
+- buf.append(">");
+- break;
+- case '\"':
+- buf.append(""");
+- break;
+- case '&':
+- buf.append("&");
+- break;
+- default:
+- buf.append(c);
+- break;
+- }
+- }
+- return buf.toString();
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/EventDetails.java b/src/main/java/org/apache/log4j/chainsaw/EventDetails.java
+deleted file mode 100644
+index 4b3ad94..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/EventDetails.java
++++ /dev/null
+@@ -1,135 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import org.apache.log4j.Priority;
+-import org.apache.log4j.spi.LoggingEvent;
+-
+-/**
+- * Represents the details of a logging event. It is intended to overcome the
+- * problem that a LoggingEvent cannot be constructed with purely fake data.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- * @version 1.0
+- */
+-class EventDetails {
+-
+- /** the time of the event **/
+- private final long mTimeStamp;
+- /** the priority of the event **/
+- private final Priority mPriority;
+- /** the category of the event **/
+- private final String mCategoryName;
+- /** the NDC for the event **/
+- private final String mNDC;
+- /** the thread for the event **/
+- private final String mThreadName;
+- /** the msg for the event **/
+- private final String mMessage;
+- /** the throwable details the event **/
+- private final String[] mThrowableStrRep;
+- /** the location details for the event **/
+- private final String mLocationDetails;
+-
+- /**
+- * Creates a new <code>EventDetails</code> instance.
+- * @param aTimeStamp a <code>long</code> value
+- * @param aPriority a <code>Priority</code> value
+- * @param aCategoryName a <code>String</code> value
+- * @param aNDC a <code>String</code> value
+- * @param aThreadName a <code>String</code> value
+- * @param aMessage a <code>String</code> value
+- * @param aThrowableStrRep a <code>String[]</code> value
+- * @param aLocationDetails a <code>String</code> value
+- */
+- EventDetails(long aTimeStamp,
+- Priority aPriority,
+- String aCategoryName,
+- String aNDC,
+- String aThreadName,
+- String aMessage,
+- String[] aThrowableStrRep,
+- String aLocationDetails)
+- {
+- mTimeStamp = aTimeStamp;
+- mPriority = aPriority;
+- mCategoryName = aCategoryName;
+- mNDC = aNDC;
+- mThreadName = aThreadName;
+- mMessage = aMessage;
+- mThrowableStrRep = aThrowableStrRep;
+- mLocationDetails = aLocationDetails;
+- }
+-
+- /**
+- * Creates a new <code>EventDetails</code> instance.
+- *
+- * @param aEvent a <code>LoggingEvent</code> value
+- */
+- EventDetails(LoggingEvent aEvent) {
+-
+- this(aEvent.timeStamp,
+- aEvent.getLevel(),
+- aEvent.getLoggerName(),
+- aEvent.getNDC(),
+- aEvent.getThreadName(),
+- aEvent.getRenderedMessage(),
+- aEvent.getThrowableStrRep(),
+- (aEvent.getLocationInformation() == null)
+- ? null : aEvent.getLocationInformation().fullInfo);
+- }
+-
+- /** @see #mTimeStamp **/
+- long getTimeStamp() {
+- return mTimeStamp;
+- }
+-
+- /** @see #mPriority **/
+- Priority getPriority() {
+- return mPriority;
+- }
+-
+- /** @see #mCategoryName **/
+- String getCategoryName() {
+- return mCategoryName;
+- }
+-
+- /** @see #mNDC **/
+- String getNDC() {
+- return mNDC;
+- }
+-
+- /** @see #mThreadName **/
+- String getThreadName() {
+- return mThreadName;
+- }
+-
+- /** @see #mMessage **/
+- String getMessage() {
+- return mMessage;
+- }
+-
+- /** @see #mLocationDetails **/
+- String getLocationDetails(){
+- return mLocationDetails;
+- }
+-
+- /** @see #mThrowableStrRep **/
+- String[] getThrowableStrRep() {
+- return mThrowableStrRep;
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/ExitAction.java b/src/main/java/org/apache/log4j/chainsaw/ExitAction.java
+deleted file mode 100644
+index 55a100e..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/ExitAction.java
++++ /dev/null
+@@ -1,48 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.awt.event.ActionEvent;
+-import javax.swing.AbstractAction;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * Encapsulates the action to exit.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- * @version 1.0
+- */
+-class ExitAction
+- extends AbstractAction
+-{
+- /** use to log messages **/
+- private static final Logger LOG = Logger.getLogger(ExitAction.class);
+- /** The instance to share **/
+- public static final ExitAction INSTANCE = new ExitAction();
+-
+- /** Stop people creating instances **/
+- private ExitAction() {}
+-
+- /**
+- * Will shutdown the application.
+- * @param aIgnore ignored
+- */
+- public void actionPerformed(ActionEvent aIgnore) {
+- LOG.info("shutting down");
+- System.exit(0);
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/LoadXMLAction.java b/src/main/java/org/apache/log4j/chainsaw/LoadXMLAction.java
+deleted file mode 100644
+index 33e5d13..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/LoadXMLAction.java
++++ /dev/null
+@@ -1,139 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.awt.event.ActionEvent;
+-import java.io.File;
+-import java.io.IOException;
+-import java.io.StringReader;
+-import javax.swing.AbstractAction;
+-import javax.swing.JFileChooser;
+-import javax.swing.JFrame;
+-import javax.swing.JOptionPane;
+-import javax.xml.parsers.ParserConfigurationException;
+-import javax.xml.parsers.SAXParserFactory;
+-import org.apache.log4j.Logger;
+-import org.xml.sax.InputSource;
+-import org.xml.sax.SAXException;
+-import org.xml.sax.XMLReader;
+-
+-/**
+- * Encapsulates the action to load an XML file.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- * @version 1.0
+- */
+-class LoadXMLAction
+- extends AbstractAction
+-{
+- /** use to log messages **/
+- private static final Logger LOG = Logger.getLogger(LoadXMLAction.class);
+-
+- /** the parent frame **/
+- private final JFrame mParent;
+-
+- /**
+- * the file chooser - configured to allow only the selection of a
+- * single file.
+- */
+- private final JFileChooser mChooser = new JFileChooser();
+- {
+- mChooser.setMultiSelectionEnabled(false);
+- mChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+- }
+-
+- /** parser to read XML files **/
+- private final XMLReader mParser;
+- /** the content handler **/
+- private final XMLFileHandler mHandler;
+-
+-
+- /**
+- * Creates a new <code>LoadXMLAction</code> instance.
+- *
+- * @param aParent the parent frame
+- * @param aModel the model to add events to
+- * @exception SAXException if an error occurs
+- * @throws ParserConfigurationException if an error occurs
+- */
+- LoadXMLAction(JFrame aParent, MyTableModel aModel)
+- throws SAXException, ParserConfigurationException
+- {
+- mParent = aParent;
+- mHandler = new XMLFileHandler(aModel);
+- mParser = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+- mParser.setContentHandler(mHandler);
+- }
+-
+- /**
+- * Prompts the user for a file to load events from.
+- * @param aIgnore an <code>ActionEvent</code> value
+- */
+- public void actionPerformed(ActionEvent aIgnore) {
+- LOG.info("load file called");
+- if (mChooser.showOpenDialog(mParent) == JFileChooser.APPROVE_OPTION) {
+- LOG.info("Need to load a file");
+- final File chosen = mChooser.getSelectedFile();
+- LOG.info("loading the contents of " + chosen.getAbsolutePath());
+- try {
+- final int num = loadFile(chosen.getAbsolutePath());
+- JOptionPane.showMessageDialog(
+- mParent,
+- "Loaded " + num + " events.",
+- "CHAINSAW",
+- JOptionPane.INFORMATION_MESSAGE);
+- } catch (Exception e) {
+- LOG.warn("caught an exception loading the file", e);
+- JOptionPane.showMessageDialog(
+- mParent,
+- "Error parsing file - " + e.getMessage(),
+- "CHAINSAW",
+- JOptionPane.ERROR_MESSAGE);
+- }
+- }
+- }
+-
+- /**
+- * Loads the contents of file into the model
+- *
+- * @param aFile the file to extract events from
+- * @return the number of events loaded
+- * @throws SAXException if an error occurs
+- * @throws IOException if an error occurs
+- */
+- private int loadFile(String aFile)
+- throws SAXException, IOException
+- {
+- synchronized (mParser) {
+- // Create a dummy document to parse the file
+- final StringBuffer buf = new StringBuffer();
+- buf.append("<?xml version=\"1.0\" standalone=\"yes\"?>\n");
+- buf.append("<!DOCTYPE log4j:eventSet ");
+- buf.append("[<!ENTITY data SYSTEM \"file:///");
+- buf.append(aFile);
+- buf.append("\">]>\n");
+- buf.append("<log4j:eventSet xmlns:log4j=\"Claira\">\n");
+- buf.append("&data;\n");
+- buf.append("</log4j:eventSet>\n");
+-
+- final InputSource is =
+- new InputSource(new StringReader(buf.toString()));
+- mParser.parse(is);
+- return mHandler.getNumEvents();
+- }
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java b/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
+deleted file mode 100644
+index ca087ad..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java
++++ /dev/null
+@@ -1,121 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.io.EOFException;
+-import java.io.IOException;
+-import java.io.ObjectInputStream;
+-import java.net.ServerSocket;
+-import java.net.Socket;
+-import java.net.SocketException;
+-import org.apache.log4j.Logger;
+-import org.apache.log4j.spi.LoggingEvent;
+-
+-/**
+- * A daemon thread the processes connections from a
+- * <code>org.apache.log4j.net.SocketAppender.html</code>.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+-class LoggingReceiver extends Thread {
+- /** used to log messages **/
+- private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
+-
+- /**
+- * Helper that actually processes a client connection. It receives events
+- * and adds them to the supplied model.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+- private class Slurper implements Runnable {
+- /** socket connection to read events from **/
+- private final Socket mClient;
+-
+- /**
+- * Creates a new <code>Slurper</code> instance.
+- *
+- * @param aClient socket to receive events from
+- */
+- Slurper(Socket aClient) {
+- mClient = aClient;
+- }
+-
+- /** loops getting the events **/
+- public void run() {
+- LOG.debug("Starting to get data");
+- try {
+- final ObjectInputStream ois =
+- new ObjectInputStream(mClient.getInputStream());
+- while (true) {
+- final LoggingEvent event = (LoggingEvent) ois.readObject();
+- mModel.addEvent(new EventDetails(event));
+- }
+- } catch (EOFException e) {
+- LOG.info("Reached EOF, closing connection");
+- } catch (SocketException e) {
+- LOG.info("Caught SocketException, closing connection");
+- } catch (IOException e) {
+- LOG.warn("Got IOException, closing connection", e);
+- } catch (ClassNotFoundException e) {
+- LOG.warn("Got ClassNotFoundException, closing connection", e);
+- }
+-
+- try {
+- mClient.close();
+- } catch (IOException e) {
+- LOG.warn("Error closing connection", e);
+- }
+- }
+- }
+-
+- /** where to put the events **/
+- private MyTableModel mModel;
+-
+- /** server for listening for connections **/
+- private ServerSocket mSvrSock;
+-
+- /**
+- * Creates a new <code>LoggingReceiver</code> instance.
+- *
+- * @param aModel model to place put received into
+- * @param aPort port to listen on
+- * @throws IOException if an error occurs
+- */
+- LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
+- setDaemon(true);
+- mModel = aModel;
+- mSvrSock = new ServerSocket(aPort);
+- }
+-
+- /** Listens for client connections **/
+- public void run() {
+- LOG.info("Thread started");
+- try {
+- while (true) {
+- LOG.debug("Waiting for a connection");
+- final Socket client = mSvrSock.accept();
+- LOG.debug("Got a connection from " +
+- client.getInetAddress().getHostName());
+- final Thread t = new Thread(new Slurper(client));
+- t.setDaemon(true);
+- t.start();
+- }
+- } catch (IOException e) {
+- LOG.error("Error in accepting connections, stopping.", e);
+- }
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/Main.java b/src/main/java/org/apache/log4j/chainsaw/Main.java
+deleted file mode 100644
+index c0c9aad..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/Main.java
++++ /dev/null
+@@ -1,192 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.awt.BorderLayout;
+-import java.awt.Dimension;
+-import java.awt.event.WindowAdapter;
+-import java.awt.event.WindowEvent;
+-import java.io.IOException;
+-import java.util.Properties;
+-import javax.swing.BorderFactory;
+-import javax.swing.JFrame;
+-import javax.swing.JMenu;
+-import javax.swing.JMenuBar;
+-import javax.swing.JMenuItem;
+-import javax.swing.JOptionPane;
+-import javax.swing.JPanel;
+-import javax.swing.JScrollPane;
+-import javax.swing.JSplitPane;
+-import javax.swing.JTable;
+-import javax.swing.ListSelectionModel;
+-import org.apache.log4j.Logger;
+-import org.apache.log4j.PropertyConfigurator;
+-
+-/**
+- * The main application.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+-public class Main
+- extends JFrame
+-{
+- /** the default port number to listen on **/
+- private static final int DEFAULT_PORT = 4445;
+-
+- /** name of property for port name **/
+- public static final String PORT_PROP_NAME = "chainsaw.port";
+-
+- /** use to log messages **/
+- private static final Logger LOG = Logger.getLogger(Main.class);
+-
+-
+- /**
+- * Creates a new <code>Main</code> instance.
+- */
+- private Main() {
+- super("CHAINSAW - Log4J Log Viewer");
+- // create the all important model
+- final MyTableModel model = new MyTableModel();
+-
+- //Create the menu bar.
+- final JMenuBar menuBar = new JMenuBar();
+- setJMenuBar(menuBar);
+- final JMenu menu = new JMenu("File");
+- menuBar.add(menu);
+-
+- try {
+- final LoadXMLAction lxa = new LoadXMLAction(this, model);
+- final JMenuItem loadMenuItem = new JMenuItem("Load file...");
+- menu.add(loadMenuItem);
+- loadMenuItem.addActionListener(lxa);
+- } catch (NoClassDefFoundError e) {
+- LOG.info("Missing classes for XML parser", e);
+- JOptionPane.showMessageDialog(
+- this,
+- "XML parser not in classpath - unable to load XML events.",
+- "CHAINSAW",
+- JOptionPane.ERROR_MESSAGE);
+- } catch (Exception e) {
+- LOG.info("Unable to create the action to load XML files", e);
+- JOptionPane.showMessageDialog(
+- this,
+- "Unable to create a XML parser - unable to load XML events.",
+- "CHAINSAW",
+- JOptionPane.ERROR_MESSAGE);
+- }
+-
+- final JMenuItem exitMenuItem = new JMenuItem("Exit");
+- menu.add(exitMenuItem);
+- exitMenuItem.addActionListener(ExitAction.INSTANCE);
+-
+- // Add control panel
+- final ControlPanel cp = new ControlPanel(model);
+- getContentPane().add(cp, BorderLayout.NORTH);
+-
+- // Create the table
+- final JTable table = new JTable(model);
+- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+- final JScrollPane scrollPane = new JScrollPane(table);
+- scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
+- scrollPane.setPreferredSize(new Dimension(900, 300));
+-
+- // Create the details
+- final JPanel details = new DetailPanel(table, model);
+- details.setPreferredSize(new Dimension(900, 300));
+-
+- // Add the table and stack trace into a splitter
+- final JSplitPane jsp =
+- new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
+- getContentPane().add(jsp, BorderLayout.CENTER);
+-
+- addWindowListener(new WindowAdapter() {
+- public void windowClosing(WindowEvent aEvent) {
+- ExitAction.INSTANCE.actionPerformed(null);
+- }
+- });
+-
+- pack();
+- setVisible(true);
+-
+- setupReceiver(model);
+- }
+-
+- /**
+- * Setup recieving messages.
+- *
+- * @param aModel a <code>MyTableModel</code> value
+- */
+- private void setupReceiver(MyTableModel aModel) {
+- int port = DEFAULT_PORT;
+- final String strRep = System.getProperty(PORT_PROP_NAME);
+- if (strRep != null) {
+- try {
+- port = Integer.parseInt(strRep);
+- } catch (NumberFormatException nfe) {
+- LOG.fatal("Unable to parse " + PORT_PROP_NAME +
+- " property with value " + strRep + ".");
+- JOptionPane.showMessageDialog(
+- this,
+- "Unable to parse port number from '" + strRep +
+- "', quitting.",
+- "CHAINSAW",
+- JOptionPane.ERROR_MESSAGE);
+- System.exit(1);
+- }
+- }
+-
+- try {
+- final LoggingReceiver lr = new LoggingReceiver(aModel, port);
+- lr.start();
+- } catch (IOException e) {
+- LOG.fatal("Unable to connect to socket server, quiting", e);
+- JOptionPane.showMessageDialog(
+- this,
+- "Unable to create socket on port " + port + ", quitting.",
+- "CHAINSAW",
+- JOptionPane.ERROR_MESSAGE);
+- System.exit(1);
+- }
+- }
+-
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // static methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+-
+- /** initialise log4j **/
+- private static void initLog4J() {
+- final Properties props = new Properties();
+- props.setProperty("log4j.rootLogger", "DEBUG, A1");
+- props.setProperty("log4j.appender.A1",
+- "org.apache.log4j.ConsoleAppender");
+- props.setProperty("log4j.appender.A1.layout",
+- "org.apache.log4j.TTCCLayout");
+- PropertyConfigurator.configure(props);
+- }
+-
+- /**
+- * The main method.
+- *
+- * @param aArgs ignored
+- */
+- public static void main(String[] aArgs) {
+- initLog4J();
+- new Main();
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java b/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
+deleted file mode 100644
+index 0d43272..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
++++ /dev/null
+@@ -1,390 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.text.DateFormat;
+-import java.util.ArrayList;
+-import java.util.Comparator;
+-import java.util.Date;
+-import java.util.Iterator;
+-import java.util.List;
+-import java.util.SortedSet;
+-import java.util.TreeSet;
+-import javax.swing.table.AbstractTableModel;
+-import org.apache.log4j.Priority;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * Represents a list of <code>EventDetails</code> objects that are sorted on
+- * logging time. Methods are provided to filter the events that are visible.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+-class MyTableModel
+- extends AbstractTableModel
+-{
+-
+- /** used to log messages **/
+- private static final Logger LOG = Logger.getLogger(MyTableModel.class);
+-
+- /** use the compare logging events **/
+- private static final Comparator MY_COMP = new Comparator()
+- {
+- /** @see Comparator **/
+- public int compare(Object aObj1, Object aObj2) {
+- if ((aObj1 == null) && (aObj2 == null)) {
+- return 0; // treat as equal
+- } else if (aObj1 == null) {
+- return -1; // null less than everything
+- } else if (aObj2 == null) {
+- return 1; // think about it. :->
+- }
+-
+- // will assume only have LoggingEvent
+- final EventDetails le1 = (EventDetails) aObj1;
+- final EventDetails le2 = (EventDetails) aObj2;
+-
+- if (le1.getTimeStamp() < le2.getTimeStamp()) {
+- return 1;
+- }
+- // assume not two events are logged at exactly the same time
+- return -1;
+- }
+- };
+-
+- /**
+- * Helper that actually processes incoming events.
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- */
+- private class Processor
+- implements Runnable
+- {
+- /** loops getting the events **/
+- public void run() {
+- while (true) {
+- try {
+- Thread.sleep(1000);
+- } catch (InterruptedException e) {
+- // ignore
+- }
+-
+- synchronized (mLock) {
+- if (mPaused) {
+- continue;
+- }
+-
+- boolean toHead = true; // were events added to head
+- boolean needUpdate = false;
+- final Iterator it = mPendingEvents.iterator();
+- while (it.hasNext()) {
+- final EventDetails event = (EventDetails) it.next();
+- mAllEvents.add(event);
+- toHead = toHead && (event == mAllEvents.first());
+- needUpdate = needUpdate || matchFilter(event);
+- }
+- mPendingEvents.clear();
+-
+- if (needUpdate) {
+- updateFilteredEvents(toHead);
+- }
+- }
+- }
+-
+- }
+- }
+-
+-
+- /** names of the columns in the table **/
+- private static final String[] COL_NAMES = {
+- "Time", "Priority", "Trace", "Category", "NDC", "Message"};
+-
+- /** definition of an empty list **/
+- private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
+-
+- /** used to format dates **/
+- private static final DateFormat DATE_FORMATTER =
+- DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
+-
+- /** the lock to control access **/
+- private final Object mLock = new Object();
+- /** set of all logged events - not filtered **/
+- private final SortedSet mAllEvents = new TreeSet(MY_COMP);
+- /** events that are visible after filtering **/
+- private EventDetails[] mFilteredEvents = EMPTY_LIST;
+- /** list of events that are buffered for processing **/
+- private final List mPendingEvents = new ArrayList();
+- /** indicates whether event collection is paused to the UI **/
+- private boolean mPaused = false;
+-
+- /** filter for the thread **/
+- private String mThreadFilter = "";
+- /** filter for the message **/
+- private String mMessageFilter = "";
+- /** filter for the NDC **/
+- private String mNDCFilter = "";
+- /** filter for the category **/
+- private String mCategoryFilter = "";
+- /** filter for the priority **/
+- private Priority mPriorityFilter = Priority.DEBUG;
+-
+-
+- /**
+- * Creates a new <code>MyTableModel</code> instance.
+- *
+- */
+- MyTableModel() {
+- final Thread t = new Thread(new Processor());
+- t.setDaemon(true);
+- t.start();
+- }
+-
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // Table Methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+- /** @see javax.swing.table.TableModel **/
+- public int getRowCount() {
+- synchronized (mLock) {
+- return mFilteredEvents.length;
+- }
+- }
+-
+- /** @see javax.swing.table.TableModel **/
+- public int getColumnCount() {
+- // does not need to be synchronized
+- return COL_NAMES.length;
+- }
+-
+- /** @see javax.swing.table.TableModel **/
+- public String getColumnName(int aCol) {
+- // does not need to be synchronized
+- return COL_NAMES[aCol];
+- }
+-
+- /** @see javax.swing.table.TableModel **/
+- public Class getColumnClass(int aCol) {
+- // does not need to be synchronized
+- return (aCol == 2) ? Boolean.class : Object.class;
+- }
+-
+- /** @see javax.swing.table.TableModel **/
+- public Object getValueAt(int aRow, int aCol) {
+- synchronized (mLock) {
+- final EventDetails event = mFilteredEvents[aRow];
+-
+- if (aCol == 0) {
+- return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
+- } else if (aCol == 1) {
+- return event.getPriority();
+- } else if (aCol == 2) {
+- return (event.getThrowableStrRep() == null)
+- ? Boolean.FALSE : Boolean.TRUE;
+- } else if (aCol == 3) {
+- return event.getCategoryName();
+- } else if (aCol == 4) {
+- return event.getNDC();
+- }
+- return event.getMessage();
+- }
+- }
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // Public Methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+- /**
+- * Sets the priority to filter events on. Only events of equal or higher
+- * property are now displayed.
+- *
+- * @param aPriority the priority to filter on
+- */
+- public void setPriorityFilter(Priority aPriority) {
+- synchronized (mLock) {
+- mPriorityFilter = aPriority;
+- updateFilteredEvents(false);
+- }
+- }
+-
+- /**
+- * Set the filter for the thread field.
+- *
+- * @param aStr the string to match
+- */
+- public void setThreadFilter(String aStr) {
+- synchronized (mLock) {
+- mThreadFilter = aStr.trim();
+- updateFilteredEvents(false);
+- }
+- }
+-
+- /**
+- * Set the filter for the message field.
+- *
+- * @param aStr the string to match
+- */
+- public void setMessageFilter(String aStr) {
+- synchronized (mLock) {
+- mMessageFilter = aStr.trim();
+- updateFilteredEvents(false);
+- }
+- }
+-
+- /**
+- * Set the filter for the NDC field.
+- *
+- * @param aStr the string to match
+- */
+- public void setNDCFilter(String aStr) {
+- synchronized (mLock) {
+- mNDCFilter = aStr.trim();
+- updateFilteredEvents(false);
+- }
+- }
+-
+- /**
+- * Set the filter for the category field.
+- *
+- * @param aStr the string to match
+- */
+- public void setCategoryFilter(String aStr) {
+- synchronized (mLock) {
+- mCategoryFilter = aStr.trim();
+- updateFilteredEvents(false);
+- }
+- }
+-
+- /**
+- * Add an event to the list.
+- *
+- * @param aEvent a <code>EventDetails</code> value
+- */
+- public void addEvent(EventDetails aEvent) {
+- synchronized (mLock) {
+- mPendingEvents.add(aEvent);
+- }
+- }
+-
+- /**
+- * Clear the list of all events.
+- */
+- public void clear() {
+- synchronized (mLock) {
+- mAllEvents.clear();
+- mFilteredEvents = new EventDetails[0];
+- mPendingEvents.clear();
+- fireTableDataChanged();
+- }
+- }
+-
+- /** Toggle whether collecting events **/
+- public void toggle() {
+- synchronized (mLock) {
+- mPaused = !mPaused;
+- }
+- }
+-
+- /** @return whether currently paused collecting events **/
+- public boolean isPaused() {
+- synchronized (mLock) {
+- return mPaused;
+- }
+- }
+-
+- /**
+- * Get the throwable information at a specified row in the filtered events.
+- *
+- * @param aRow the row index of the event
+- * @return the throwable information
+- */
+- public EventDetails getEventDetails(int aRow) {
+- synchronized (mLock) {
+- return mFilteredEvents[aRow];
+- }
+- }
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // Private methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+- /**
+- * Update the filtered events data structure.
+- * @param aInsertedToFront indicates whether events were added to front of
+- * the events. If true, then the current first event must still exist
+- * in the list after the filter is applied.
+- */
+- private void updateFilteredEvents(boolean aInsertedToFront) {
+- final long start = System.currentTimeMillis();
+- final List filtered = new ArrayList();
+- final int size = mAllEvents.size();
+- final Iterator it = mAllEvents.iterator();
+-
+- while (it.hasNext()) {
+- final EventDetails event = (EventDetails) it.next();
+- if (matchFilter(event)) {
+- filtered.add(event);
+- }
+- }
+-
+- final EventDetails lastFirst = (mFilteredEvents.length == 0)
+- ? null
+- : mFilteredEvents[0];
+- mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
+-
+- if (aInsertedToFront && (lastFirst != null)) {
+- final int index = filtered.indexOf(lastFirst);
+- if (index < 1) {
+- LOG.warn("In strange state");
+- fireTableDataChanged();
+- } else {
+- fireTableRowsInserted(0, index - 1);
+- }
+- } else {
+- fireTableDataChanged();
+- }
+-
+- final long end = System.currentTimeMillis();
+- LOG.debug("Total time [ms]: " + (end - start)
+- + " in update, size: " + size);
+- }
+-
+- /**
+- * Returns whether an event matches the filters.
+- *
+- * @param aEvent the event to check for a match
+- * @return whether the event matches
+- */
+- private boolean matchFilter(EventDetails aEvent) {
+- if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
+- (aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
+- (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
+- ((mNDCFilter.length() == 0) ||
+- ((aEvent.getNDC() != null) &&
+- (aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
+- {
+- final String rm = aEvent.getMessage();
+- if (rm == null) {
+- // only match if we have not filtering in place
+- return (mMessageFilter.length() == 0);
+- } else {
+- return (rm.indexOf(mMessageFilter) >= 0);
+- }
+- }
+-
+- return false; // by default not match
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java b/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
+deleted file mode 100644
+index 2f9af51..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
++++ /dev/null
+@@ -1,170 +0,0 @@
+-/*
+- * 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.chainsaw;
+-
+-import java.util.StringTokenizer;
+-import org.apache.log4j.Level;
+-import org.xml.sax.Attributes;
+-import org.xml.sax.SAXException;
+-import org.xml.sax.helpers.DefaultHandler;
+-
+-/**
+- * A content handler for document containing Log4J events logged using the
+- * XMLLayout class. It will create events and add them to a supplied model.
+- *
+- * @author <a href="mailto:oliver at puppycrawl.com">Oliver Burn</a>
+- * @version 1.0
+- */
+-class XMLFileHandler
+- extends DefaultHandler
+-{
+- /** represents the event tag **/
+- private static final String TAG_EVENT = "log4j:event";
+- /** represents the message tag **/
+- private static final String TAG_MESSAGE = "log4j:message";
+- /** represents the ndc tag **/
+- private static final String TAG_NDC = "log4j:NDC";
+- /** represents the throwable tag **/
+- private static final String TAG_THROWABLE = "log4j:throwable";
+- /** represents the location info tag **/
+- private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
+-
+- /** where to put the events **/
+- private final MyTableModel mModel;
+- /** the number of events in the document **/
+- private int mNumEvents;
+-
+- /** the time of the event **/
+- private long mTimeStamp;
+- /** the priority (level) of the event **/
+- private Level mLevel;
+- /** the category of the event **/
+- private String mCategoryName;
+- /** the NDC for the event **/
+- private String mNDC;
+- /** the thread for the event **/
+- private String mThreadName;
+- /** the msg for the event **/
+- private String mMessage;
+- /** the throwable details the event **/
+- private String[] mThrowableStrRep;
+- /** the location details for the event **/
+- private String mLocationDetails;
+- /** buffer for collecting text **/
+- private final StringBuffer mBuf = new StringBuffer();
+-
+- /**
+- * Creates a new <code>XMLFileHandler</code> instance.
+- *
+- * @param aModel where to add the events
+- */
+- XMLFileHandler(MyTableModel aModel) {
+- mModel = aModel;
+- }
+-
+- /** @see DefaultHandler **/
+- public void startDocument()
+- throws SAXException
+- {
+- mNumEvents = 0;
+- }
+-
+- /** @see DefaultHandler **/
+- public void characters(char[] aChars, int aStart, int aLength) {
+- mBuf.append(String.valueOf(aChars, aStart, aLength));
+- }
+-
+- /** @see DefaultHandler **/
+- public void endElement(String aNamespaceURI,
+- String aLocalName,
+- String aQName)
+- {
+- if (TAG_EVENT.equals(aQName)) {
+- addEvent();
+- resetData();
+- } else if (TAG_NDC.equals(aQName)) {
+- mNDC = mBuf.toString();
+- } else if (TAG_MESSAGE.equals(aQName)) {
+- mMessage = mBuf.toString();
+- } else if (TAG_THROWABLE.equals(aQName)) {
+- final StringTokenizer st =
+- new StringTokenizer(mBuf.toString(), "\n\t");
+- mThrowableStrRep = new String[st.countTokens()];
+- if (mThrowableStrRep.length > 0) {
+- mThrowableStrRep[0] = st.nextToken();
+- for (int i = 1; i < mThrowableStrRep.length; i++) {
+- mThrowableStrRep[i] = "\t" + st.nextToken();
+- }
+- }
+- }
+- }
+-
+- /** @see DefaultHandler **/
+- public void startElement(String aNamespaceURI,
+- String aLocalName,
+- String aQName,
+- Attributes aAtts)
+- {
+- mBuf.setLength(0);
+-
+- if (TAG_EVENT.equals(aQName)) {
+- mThreadName = aAtts.getValue("thread");
+- mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
+- mCategoryName = aAtts.getValue("logger");
+- mLevel = Level.toLevel(aAtts.getValue("level"));
+- } else if (TAG_LOCATION_INFO.equals(aQName)) {
+- mLocationDetails = aAtts.getValue("class") + "."
+- + aAtts.getValue("method")
+- + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+- + ")";
+- }
+- }
+-
+- /** @return the number of events in the document **/
+- int getNumEvents() {
+- return mNumEvents;
+- }
+-
+- ////////////////////////////////////////////////////////////////////////////
+- // Private methods
+- ////////////////////////////////////////////////////////////////////////////
+-
+- /** Add an event to the model **/
+- private void addEvent() {
+- mModel.addEvent(new EventDetails(mTimeStamp,
+- mLevel,
+- mCategoryName,
+- mNDC,
+- mThreadName,
+- mMessage,
+- mThrowableStrRep,
+- mLocationDetails));
+- mNumEvents++;
+- }
+-
+- /** Reset the data for an event **/
+- private void resetData() {
+- mTimeStamp = 0;
+- mLevel = null;
+- mCategoryName = null;
+- mNDC = null;
+- mThreadName = null;
+- mMessage = null;
+- mThrowableStrRep = null;
+- mLocationDetails = null;
+- }
+-}
+diff --git a/src/main/java/org/apache/log4j/chainsaw/package.html b/src/main/java/org/apache/log4j/chainsaw/package.html
+deleted file mode 100644
+index 5b01480..0000000
+--- a/src/main/java/org/apache/log4j/chainsaw/package.html
++++ /dev/null
+@@ -1,118 +0,0 @@
+-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+-<!--
+- 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.
+-
+--->
+-
+-<HTML>
+- <HEAD>
+- <TITLE>Chainsaw Tool</TITLE>
+- </head>
+-
+- <BODY>
+-
+- <P>Chainsaw is a GUI log viewer and filter for the log4j
+-package. By default it listens for <a
+-href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
+-the <A href="../net/SocketAppender.html">SocketAppender</A> and
+-displays them in a table. The events can be filtered based on:</P>
+-
+- <UL>
+- <LI>Level </li>
+-
+- <LI>Thread name</li>
+-
+- <LI>Logger</li>
+- <LI>Message</li>
+-
+- <LI>NDC</LI>
+- </UL>
+-
+- <P>All the details for each event can be displayed by selecting
+- the event in the table.</P>
+-
+- <P>Chainsaw also supports loading a events logged to a file using
+- the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
+- is great for analysing log files, and means you do not need to
+- keep Chainsaw running continously. It is easy to add support
+- for loading events from other sources like JDBC.</P>
+-
+- <P>A picture is worth a thousand words: </P>
+-
+- <P align=center><A
+- href="doc-files/screen_01.png"><IMG
+- height="50%" alt="Screen shot of chainsaw"
+- src="doc-files/screen_01.png"
+- width="50%"></A>.</P>
+-
+- <P>Finally, why is it called chainsaw?
+- Because it cuts your log (file) down to size. :-)
+- </P>
+-
+-
+- <H2>Requirements</H2>
+-
+- <P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
+-
+-
+- <H2>Running chainsaw</H2>
+-
+- <H3>Setup</H3>
+- <P>You need to include the <code>log4j.jar</code> in the classpath.
+-
+- <H3>Usage</H3>
+-
+- <P>The command line usage is:</P>
+-
+- <PRE> java -D<property>=<value> org.apache.log4j.chainsaw.Main </PRE>
+-
+- <P>The default behaviour of chainsaw can be changed by setting system properties
+- using the <CODE>-D<property>=<value></CODE> arguments to java. The
+- following table describes what properties can be set:</P>
+-
+- <TABLE cellSpacing=0 cellPadding=2 border=1>
+-
+- <TR>
+- <TD vAlign=top><B>Property</B></TD>
+- <TD vAlign=top><B>Description</B></TD></TR>
+- <TR>
+- <TD vAlign=top>chainsaw.port</TD>
+- <TD vAlign=top>Indicates which port to listen for connections on. Defaults
+- to <SPAN class=default>"4445"</SPAN>.
+- </TD>
+- </TR>
+- </TBODY>
+- </TABLE>
+-
+- <H2>Configuring Log4J</H2>
+-
+- <P>You will need to configure log4j to send logging events to
+- Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
+- for sending logging events to Chainsaw.</P>
+-
+-<PRE>
+-log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
+-
+-log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
+-log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
+-log4j.appender.CHAINSAW_CLIENT.Port=4445
+-log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
+-</PRE>
+-
+-
+-
+- </body>
+-</html>
+\ No newline at end of file
=====================================
debian/patches/series
=====================================
@@ -1,5 +1,8 @@
build_fix.patch
-
remove-activation-framework-dependency.patch
add-missing-classes.patch
CVE-2019-17571.patch
+CVE-2022-23305.patch
+CVE-2022-23302.patch
+CVE-2022-23307.patch
+CVE-2021-4104.patch
View it on GitLab: https://salsa.debian.org/java-team/apache-log4j1.2/-/compare/f3b7ea09e881ab3dbdf111152ba7bf339416822c...406287ebf5aabc20330e8130d96b1e2af410b948
--
View it on GitLab: https://salsa.debian.org/java-team/apache-log4j1.2/-/compare/f3b7ea09e881ab3dbdf111152ba7bf339416822c...406287ebf5aabc20330e8130d96b1e2af410b948
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20220212/078e5b69/attachment.htm>
More information about the pkg-java-commits
mailing list