Have most receivers converted to be new style.  Most are untested
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java
index c93521e..2080359 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java
@@ -20,7 +20,8 @@
 import org.apache.log4j.chainsaw.logevents.Level;
 
 /**
- * A receiver receives log events from a source.
+ * A receiver receives log events from a source.  A ChainsawReceiver will create
+ * from 1...N ChainsawReceiverNodes
  */
 public interface ChainsawReceiver {
     
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverNode.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverNode.java
new file mode 100644
index 0000000..ea1d748
--- /dev/null
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverNode.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * Each ChainsawReceiver may have multiple Nodes associated with it.  For example,
+ * if a ChainsawReceiver listens on a port for incoming connections, each
+ * incoming connection will create a new ChainsawReceiverNode that will read and
+ * parse messages.
+ *
+ * Other receivers may not need to create sub-nodes.
+ */
+public interface ChainsawReceiverNode {
+
+}
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 22ef132..fb706c1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1274,8 +1274,8 @@
                                             fileReceiver.setTailing(true);
                                             fileReceiver.setLogFormat(receiverPattern);
                                             fileReceiver.setTimestampFormat(timestampFormat);
-                                            fileReceiver.setThreshold(Level.TRACE);
-                                            pluginRegistry.addPlugin(fileReceiver);
+//                                            fileReceiver.setThreshold(Level.TRACE);
+//                                            pluginRegistry.addPlugin(fileReceiver);
                                             fileReceiver.activateOptions();
                                             receiversPanel.updateReceiverTreeInDispatchThread();
                                         } catch (URISyntaxException e1) {
@@ -1305,9 +1305,9 @@
                                         fileReceiver.setLogFormat(receiverConfigurationPanel.getModel().getLogFormat());
                                     }
                                     fileReceiver.setTimestampFormat(receiverConfigurationPanel.getModel().getLogFormatTimestampFormat());
-                                    fileReceiver.setThreshold(Level.TRACE);
-
-                                    pluginRegistry.addPlugin(fileReceiver);
+//                                    fileReceiver.setThreshold(Level.TRACE);
+//
+//                                    pluginRegistry.addPlugin(fileReceiver);
                                     fileReceiver.activateOptions();
                                     receiversPanel.updateReceiverTreeInDispatchThread();
                                 }
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
index 0675220..f52a156 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
@@ -27,6 +27,8 @@
 import java.awt.*;
 import java.io.*;
 import java.util.zip.GZIPInputStream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * A VFS-enabled version of org.apache.log4j.varia.LogFilePatternReceiver.
@@ -150,12 +152,15 @@
     private boolean autoReconnect;
     private VFSReader vfsReader;
 
+    private static final Logger logger = LogManager.getLogger();
+
     public VFSLogFilePatternReceiver() {
         super();
     }
 
+    @Override
     public void shutdown() {
-        getLogger().info("shutdown VFSLogFilePatternReceiver");
+        logger.info("shutdown VFSLogFilePatternReceiver");
         active = false;
         container = null;
         if (vfsReader != null) {
@@ -231,7 +236,7 @@
                     while (container == null) {
                         try {
                             waitForContainerLock.wait(1000);
-                            getLogger().debug("waiting for setContainer call");
+                            logger.debug("waiting for setContainer call");
                         } catch (InterruptedException ie) {
                         }
                     }
@@ -246,7 +251,7 @@
                         while ((containerFrame1 = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, container)) == null) {
                             try {
                                 waitForContainerLock.wait(1000);
-                                getLogger().debug("waiting for container's frame to be available");
+                                logger.debug("waiting for container's frame to be available");
                             } catch (InterruptedException ie) {
                             }
                         }
@@ -265,7 +270,7 @@
                     f.setLocation(d.width / 2, d.height / 2);
                     f.setVisible(true);
                     if (null == f.getUserName() || null == f.getPassword()) {
-                        getLogger().info("Username and password not both provided, not using credentials");
+                        logger.info("Username and password not both provided, not using credentials");
                     } else {
                         String oldURL = getFileURL();
                         int index = oldURL.indexOf("://");
@@ -305,7 +310,7 @@
                 vfsReader = new VFSReader();
                 new Thread(vfsReader).start();
             } else {
-                getLogger().info("null URL - unable to parse file");
+                logger.info("null URL - unable to parse file");
             }
         }
     }
@@ -326,7 +331,7 @@
                 int protocolIndex = getFileURL().indexOf("://");
 
                 String loggableFileURL = atIndex > -1 ? getFileURL().substring(0, protocolIndex + "://".length()) + "username:password" + getFileURL().substring(atIndex) : getFileURL();
-                getLogger().info("attempting to load file: " + loggableFileURL);
+                logger.info("attempting to load file: " + loggableFileURL);
                 try {
                     FileSystemManager fileSystemManager = VFS.getManager();
                     FileSystemOptions opts = new FileSystemOptions();
@@ -334,7 +339,7 @@
                     try {
                         SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
                     } catch (NoClassDefFoundError ncdfe) {
-                        getLogger().warn("JSch not on classpath!", ncdfe);
+                        logger.warn("JSch not on classpath!", ncdfe);
                     }
 
                     synchronized (fileSystemManager) {
@@ -349,13 +354,13 @@
                                 setPath(urlFileName.getPath());
                             }
                         } else {
-                            getLogger().info(loggableFileURL + " not available - will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis");
+                            logger.info(loggableFileURL + " not available - will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis");
                         }
                     }
                 } catch (FileSystemException fse) {
-                    getLogger().info(loggableFileURL + " not available - may be due to incorrect credentials, but will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis", fse);
+                    logger.info(loggableFileURL + " not available - may be due to incorrect credentials, but will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis", fse);
                 } catch (UnsupportedEncodingException e) {
-                    getLogger().info("UTF-8 not available", e);
+                    logger.info("UTF-8 not available", e);
                 }
                 if (reader == null) {
                     synchronized (this) {
@@ -371,7 +376,7 @@
                 return;
             }
             initialize();
-            getLogger().debug(getPath() + " exists");
+            logger.debug(getPath() + " exists");
             boolean readingFinished = false;
 
             do {
@@ -386,7 +391,7 @@
                         try {
                             SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
                         } catch (NoClassDefFoundError ncdfe) {
-                            getLogger().warn("JSch not on classpath!", ncdfe);
+                            logger.warn("JSch not on classpath!", ncdfe);
                         }
 
                         //fileobject was created above, release it and construct a new one
@@ -407,7 +412,7 @@
                                 //available in vfs as of 30 Mar 2006 - will load but not tail if not available
                                 fileObject.refresh();
                             } catch (Error err) {
-                                getLogger().info(getPath() + " - unable to refresh fileobject", err);
+                                logger.info(getPath() + " - unable to refresh fileobject", err);
                             }
 
                             if (isGZip(getFileURL())) {
@@ -420,7 +425,7 @@
                             //could have been truncated or appended to (don't do anything if same size)
                             if (fileObject.getContent().getSize() < lastFileSize) {
                                 reader = new InputStreamReader(fileObject.getContent().getInputStream(), "UTF-8");
-                                getLogger().debug(getPath() + " was truncated");
+                                logger.debug(getPath() + " was truncated");
                                 lastFileSize = 0; //seek to beginning of file
                                 lastFilePointer = 0;
                             } else if (fileObject.getContent().getSize() > lastFileSize) {
@@ -440,10 +445,10 @@
                                     reader = null;
                                 }
                             } catch (IOException ioe) {
-                                getLogger().debug(getPath() + " - unable to close reader", ioe);
+                                logger.debug(getPath() + " - unable to close reader", ioe);
                             }
                         } else {
-                            getLogger().info(getPath() + " - not available - will re-attempt to load after waiting " + getWaitMillis() + " millis");
+                            logger.info(getPath() + " - not available - will re-attempt to load after waiting " + getWaitMillis() + " millis");
                         }
 
                         try {
@@ -453,17 +458,17 @@
                         } catch (InterruptedException ie) {
                         }
                         if (isTailing() && fileLarger && !terminated) {
-                            getLogger().debug(getPath() + " - tailing file - file size: " + lastFileSize);
+                            logger.debug(getPath() + " - tailing file - file size: " + lastFileSize);
                         }
                     } while (isTailing() && !terminated && !readingFinished);
                 } catch (IOException ioe) {
-                    getLogger().info(getPath() + " - exception processing file", ioe);
+                    logger.info(getPath() + " - exception processing file", ioe);
                     try {
                         if (fileObject != null) {
                             fileObject.close();
                         }
                     } catch (FileSystemException e) {
-                        getLogger().info(getPath() + " - exception processing file", e);
+                        logger.info(getPath() + " - exception processing file", e);
                     }
                     try {
                         synchronized (this) {
@@ -473,7 +478,7 @@
                     }
                 }
             } while (isAutoReconnect() && !terminated && !readingFinished);
-            getLogger().debug(getPath() + " - processing complete");
+            logger.debug(getPath() + " - processing complete");
         }
 
         public void terminate() {
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
index ba36fa3..eb47a58 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
@@ -50,6 +50,7 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.util.*;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
 
 /**
  * This plugin is designed to detect specific Zeroconf zones (Rendevouz/Bonjour,
@@ -436,19 +437,21 @@
     private void connectTo(ServiceInfo info) {
         LOG.info("Connection request for " + info);
         //Chainsaw can construct receivers from discovered appenders
-        Receiver receiver = getReceiver(info);
+        ChainsawReceiver receiver = getReceiver(info);
         //if null, unable to resolve the service name..no-op
         if (receiver == null) {
             return;
         }
-        ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(receiver);
-        receiver.activateOptions();
-        LOG.info("Receiver '" + receiver.getName() + "' has been started");
+        // TODO tell LogUI that we have a new receiver
 
-        // ServiceInfo obeys equals() and hashCode() contracts, so this should be safe.
-        synchronized (serviceInfoToReceiveMap) {
-            serviceInfoToReceiveMap.put(info, receiver);
-        }
+//        ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(receiver);
+//        receiver.activateOptions();
+//        LOG.info("Receiver '" + receiver.getName() + "' has been started");
+//
+//        // ServiceInfo obeys equals() and hashCode() contracts, so this should be safe.
+//        synchronized (serviceInfoToReceiveMap) {
+//            serviceInfoToReceiveMap.put(info, receiver);
+//        }
 
 //         this instance of the menu item needs to be disabled, and have an icon added
         JMenuItem item = locateMatchingMenuItem(info.getName());
@@ -460,7 +463,7 @@
 //        discoveredDevices.fireContentsChanged();
     }
 
-    private Receiver getReceiver(ServiceInfo info) {
+    private ChainsawReceiver getReceiver(ServiceInfo info) {
         String zone = info.getType();
         int port = info.getPort();
         String hostAddress = info.getHostAddress();
diff --git a/src/main/java/org/apache/log4j/net/MulticastReceiver.java b/src/main/java/org/apache/log4j/net/MulticastReceiver.java
index 6e7ba3c..a256ede 100644
--- a/src/main/java/org/apache/log4j/net/MulticastReceiver.java
+++ b/src/main/java/org/apache/log4j/net/MulticastReceiver.java
@@ -20,12 +20,15 @@
 import org.apache.log4j.plugins.Pauseable;
 import org.apache.log4j.plugins.Receiver;
 import org.apache.log4j.spi.Decoder;
-import org.apache.log4j.spi.LoggingEvent;
 
 import java.io.IOException;
 import java.net.*;
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 
 /**
@@ -35,8 +38,8 @@
  *
  * @author Scott Deboy &lt;sdeboy@apache.org&gt;
  */
-public class MulticastReceiver extends Receiver implements PortBased,
-    AddressBased, Pauseable {
+public class MulticastReceiver extends ChainsawReceiverSkeleton implements PortBased,
+    AddressBased {
     private static final int PACKET_LENGTH = 16384;
     private int port;
     private String address;
@@ -46,11 +49,12 @@
     //default to log4j xml decoder
     private String decoder = "org.apache.log4j.xml.XMLDecoder";
     private Decoder decoderImpl;
-    private MulticastHandlerThread handlerThread;
     private MulticastReceiverThread receiverThread;
-    private boolean paused;
     private boolean advertiseViaMulticastDNS;
     private ZeroConfSupport zeroConf;
+    private boolean active = false;
+
+    private static final Logger logger = LogManager.getLogger();
 
     /**
      * The MulticastDNS zone advertised by a MulticastReceiver
@@ -97,9 +101,6 @@
         if (advertiseViaMulticastDNS) {
             zeroConf.unadvertise();
         }
-        if (handlerThread != null) {
-            handlerThread.interrupt();
-        }
         if (receiverThread != null) {
             receiverThread.interrupt();
         }
@@ -112,15 +113,16 @@
         this.address = address;
     }
 
-    public boolean isPaused() {
-        return paused;
+    public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+        this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
     }
 
-    public void setPaused(boolean b) {
-        paused = b;
+    public boolean isAdvertiseViaMulticastDNS() {
+        return advertiseViaMulticastDNS;
     }
 
-    public void activateOptions() {
+    @Override
+    public void start() {
         InetAddress addr = null;
 
         try {
@@ -131,9 +133,9 @@
                 this.decoderImpl = (Decoder) o;
             }
         } catch (ClassNotFoundException cnfe) {
-            getLogger().warn("Unable to find decoder", cnfe);
+            logger.warn("Unable to find decoder", cnfe);
         } catch (IllegalAccessException | InstantiationException iae) {
-            getLogger().warn("Could not construct decoder", iae);
+            logger.warn("Could not construct decoder", iae);
         }
 
         try {
@@ -148,8 +150,6 @@
             socket.joinGroup(addr);
             receiverThread = new MulticastReceiverThread();
             receiverThread.start();
-            handlerThread = new MulticastHandlerThread();
-            handlerThread.start();
             if (advertiseViaMulticastDNS) {
                 zeroConf = new ZeroConfSupport(ZONE, port, getName());
                 zeroConf.advertise();
@@ -160,12 +160,9 @@
         }
     }
 
-    public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
-        this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
-    }
-
-    public boolean isAdvertiseViaMulticastDNS() {
-        return advertiseViaMulticastDNS;
+    @Override
+    public boolean isActive() {
+        return active;
     }
 
     class MulticastHandlerThread extends Thread {
@@ -204,16 +201,7 @@
 
                     for (Object aList2 : list2) {
                         String data = (String) aList2;
-                        List<LoggingEvent> v = decoderImpl.decodeEvents(data.trim());
-
-                        if (v != null) {
-
-                            for (Object aV : v) {
-                                if (!isPaused()) {
-                                    doPost((LoggingEvent) aV);
-                                }
-                            }
-                        }
+                        
                     }
 
                     list2.clear();
@@ -246,12 +234,22 @@
 
                     //this string constructor which accepts a charset throws an exception if it is
                     //null
+                    String data;
                     if (encoding == null) {
-                        handlerThread.append(
-                            new String(p.getData(), 0, p.getLength()));
+                        data =
+                            new String(p.getData(), 0, p.getLength());
                     } else {
-                        handlerThread.append(
-                            new String(p.getData(), 0, p.getLength(), encoding));
+                        data =
+                            new String(p.getData(), 0, p.getLength(), encoding);
+                    }
+
+                    List<ChainsawLoggingEvent> v = decoderImpl.decodeEvents(data.trim());
+
+                    if (v != null) {
+
+                        for (ChainsawLoggingEvent aV : v) {
+                            append(aV);
+                        }
                     }
                 } catch (SocketException se) {
                     //disconnected
@@ -260,7 +258,7 @@
                 }
             }
 
-            getLogger().debug("{}'s thread is ending.", MulticastReceiver.this.getName());
+            logger.debug("{}'s thread is ending.", MulticastReceiver.this.getName());
         }
     }
 }
diff --git a/src/main/java/org/apache/log4j/net/MulticastReceiverFactory.java b/src/main/java/org/apache/log4j/net/MulticastReceiverFactory.java
new file mode 100644
index 0000000..6425a70
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/MulticastReceiverFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
+
+/**
+ *
+ */
+public class MulticastReceiverFactory implements ChainsawReceiverFactory{
+
+    @Override
+    public ChainsawReceiver create() {
+        return new MulticastReceiver();
+    }
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException {
+        return new PropertyDescriptor[]{
+            new PropertyDescriptor("name", MulticastReceiver.class),
+            new PropertyDescriptor("port", MulticastReceiver.class),
+            new PropertyDescriptor("address", MulticastReceiver.class),
+            new PropertyDescriptor("encoding", MulticastReceiver.class),
+            new PropertyDescriptor("decoder", MulticastReceiver.class),
+        };
+    }
+
+    @Override
+    public String getReceiverName() {
+        return "MulticastReceiver";
+    }
+
+}
diff --git a/src/main/java/org/apache/log4j/net/UDPReceiver.java b/src/main/java/org/apache/log4j/net/UDPReceiver.java
index ae990f7..b41cd39 100644
--- a/src/main/java/org/apache/log4j/net/UDPReceiver.java
+++ b/src/main/java/org/apache/log4j/net/UDPReceiver.java
@@ -28,6 +28,10 @@
 import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 
 /**
@@ -36,7 +40,7 @@
  *
  * @author Scott Deboy &lt;sdeboy@apache.org&gt;
  */
-public class UDPReceiver extends Receiver implements PortBased, Pauseable {
+public class UDPReceiver extends ChainsawReceiverSkeleton implements PortBased {
     private static final int PACKET_LENGTH = 16384;
     private UDPReceiverThread receiverThread;
     private String encoding;
@@ -44,13 +48,14 @@
     //default to log4j xml decoder
     private String decoder = "org.apache.log4j.xml.XMLDecoder";
     private Decoder decoderImpl;
-    protected boolean paused;
-    private transient boolean closed = false;
+    private boolean closed = false;
     private int port;
     private DatagramSocket socket;
-    UDPHandlerThread handlerThread;
     private boolean advertiseViaMulticastDNS;
     private ZeroConfSupport zeroConf;
+    private boolean active = true;
+
+    private static final Logger logger = LogManager.getLogger();
 
     /**
      * The MulticastDNS zone advertised by a UDPReceiver
@@ -89,14 +94,6 @@
         this.decoder = decoder;
     }
 
-    public boolean isPaused() {
-        return paused;
-    }
-
-    public void setPaused(boolean b) {
-        paused = b;
-    }
-
     public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
         this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
     }
@@ -122,10 +119,6 @@
         }
 
         try {
-            if (handlerThread != null) {
-                handlerThread.close();
-                handlerThread.join();
-            }
             if (receiverThread != null) {
                 receiverThread.join();
             }
@@ -133,13 +126,8 @@
         }
     }
 
-    /**
-     * Returns true if this receiver is active.
-     */
-//  public synchronized boolean isActive() {
-//    return isActive;
-//}
-    public void activateOptions() {
+    @Override
+    public void start() {
         try {
             Class c = Class.forName(decoder);
             Object o = c.newInstance();
@@ -148,17 +136,15 @@
                 this.decoderImpl = (Decoder) o;
             }
         } catch (ClassNotFoundException cnfe) {
-            getLogger().warn("Unable to find decoder", cnfe);
+            logger.warn("Unable to find decoder", cnfe);
         } catch (IllegalAccessException | InstantiationException iae) {
-            getLogger().warn("Could not construct decoder", iae);
+            logger.warn("Could not construct decoder", iae);
         }
 
         try {
             socket = new DatagramSocket(port);
             receiverThread = new UDPReceiverThread();
             receiverThread.start();
-            handlerThread = new UDPHandlerThread();
-            handlerThread.start();
             if (advertiseViaMulticastDNS) {
                 zeroConf = new ZeroConfSupport(ZONE, port, getName());
                 zeroConf.advertise();
@@ -169,76 +155,10 @@
         }
     }
 
-    class UDPHandlerThread extends Thread {
-        private final List<String> list = new ArrayList<>();
-
-        public UDPHandlerThread() {
-            setDaemon(true);
-        }
-
-        public void append(String data) {
-            synchronized (list) {
-                list.add(data);
-                list.notify();
-            }
-        }
-
-        /**
-         * Allow the UDPHandlerThread to wakeup and exit gracefully.
-         */
-        void close() {
-            synchronized (list) {
-                list.notify();
-            }
-        }
-
-        public void run() {
-            ArrayList<String> list2 = new ArrayList<>();
-
-            while (!UDPReceiver.this.closed) {
-                synchronized (list) {
-                    try {
-                        while (!UDPReceiver.this.closed && list.size() == 0) {
-                            list.wait(300);
-                        }
-
-                        if (list.size() > 0) {
-                            list2.addAll(list);
-                            list.clear();
-                        }
-                    } catch (InterruptedException ie) {
-                    }
-                }
-
-                if (list2.size() > 0) {
-
-                    for (Object aList2 : list2) {
-                        String data = (String) aList2;
-                        List<LoggingEvent> v = decoderImpl.decodeEvents(data);
-
-                        if (v != null) {
-
-                            for (Object aV : v) {
-                                if (!isPaused()) {
-                                    doPost((LoggingEvent) aV);
-                                }
-                            }
-                        }
-                    }
-
-                    list2.clear();
-                } else {
-                    try {
-                        synchronized (this) {
-                            wait(1000);
-                        }
-                    } catch (InterruptedException ie) {
-                    }
-                }
-            } // while
-            getLogger().debug(UDPReceiver.this.getName() + "'s handler thread is exiting");
-        } // run
-    } // UDPHandlerThread
+    @Override
+    public boolean isActive() {
+        return active;
+    }
 
     class UDPReceiverThread extends Thread {
         public UDPReceiverThread() {
@@ -255,12 +175,16 @@
 
                     //this string constructor which accepts a charset throws an exception if it is
                     //null
+                    String data;
                     if (encoding == null) {
-                        handlerThread.append(
-                            new String(p.getData(), 0, p.getLength()));
+                        data = new String(p.getData(), 0, p.getLength());
                     } else {
-                        handlerThread.append(
-                            new String(p.getData(), 0, p.getLength(), encoding));
+                        data = new String(p.getData(), 0, p.getLength(), encoding);
+                    }
+
+                    List<ChainsawLoggingEvent> v = decoderImpl.decodeEvents(data);
+                    for( ChainsawLoggingEvent evt : v ){
+                        append(evt);
                     }
                 } catch (SocketException se) {
                     //disconnected
diff --git a/src/main/java/org/apache/log4j/net/UDPReceiverFactory.java b/src/main/java/org/apache/log4j/net/UDPReceiverFactory.java
new file mode 100644
index 0000000..d6181c4
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/UDPReceiverFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
+
+/**
+ *
+ */
+public class UDPReceiverFactory implements ChainsawReceiverFactory{
+
+    @Override
+    public ChainsawReceiver create() {
+        return new UDPReceiver();
+    }
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException {
+        return new PropertyDescriptor[]{
+            new PropertyDescriptor("name", UDPReceiver.class),
+            new PropertyDescriptor("port", UDPReceiver.class),
+            new PropertyDescriptor("encoding", UDPReceiver.class),
+            new PropertyDescriptor("decoder", UDPReceiver.class),
+        };
+    }
+
+    @Override
+    public String getReceiverName() {
+        return "UDPReceiver";
+    }
+}
diff --git a/src/main/java/org/apache/log4j/net/XMLReceiverFactory.java b/src/main/java/org/apache/log4j/net/XMLReceiverFactory.java
new file mode 100644
index 0000000..a7a066c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/XMLReceiverFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
+
+/**
+ *
+ * @author robert
+ */
+public class XMLReceiverFactory implements ChainsawReceiverFactory{
+
+    @Override
+    public ChainsawReceiver create() {
+        return new XMLSocketReceiver();
+    }
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException {
+        return new PropertyDescriptor[]{
+                new PropertyDescriptor("name", XMLSocketReceiver.class),
+                new PropertyDescriptor("port", XMLSocketReceiver.class),
+            };
+    }
+
+    @Override
+    public String getReceiverName() {
+        return "XMLSocketReceiver";
+    }
+
+}
diff --git a/src/main/java/org/apache/log4j/net/XMLSocketNode.java b/src/main/java/org/apache/log4j/net/XMLSocketNode.java
index e97b7a9..e592ae1 100644
--- a/src/main/java/org/apache/log4j/net/XMLSocketNode.java
+++ b/src/main/java/org/apache/log4j/net/XMLSocketNode.java
@@ -1,201 +1,201 @@
-/*
- * 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.helpers.Constants;
-import org.apache.log4j.plugins.Receiver;
-import org.apache.log4j.spi.ComponentBase;
-import org.apache.log4j.spi.Decoder;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.LoggingEvent;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Socket;
-import java.util.List;
-
-
-/**
- * Read {@link LoggingEvent} objects sent from a remote client using XML over
- * Sockets (TCP). These logging events are logged according to local
- * policy, as if they were generated locally.
- * <p>
- * <p>For example, the socket node might decide to log events to a
- * local file and also resent them to a second socket node.
- *
- * @author Scott Deboy &lt;sdeboy@apache.org&gt;;
- * @since 0.8.4
- */
-public class XMLSocketNode extends ComponentBase implements Runnable {
-    Socket socket;
-    Receiver receiver;
-    Decoder decoder;
-    SocketNodeEventListener listener;
-
-    /**
-     * Constructor for socket and logger repository.
-     */
-    public XMLSocketNode(
-        String decoder, Socket socket, LoggerRepository hierarchy) {
-        this.repository = hierarchy;
-        try {
-            Class c = Class.forName(decoder);
-            Object o = c.newInstance();
-
-            if (o instanceof Decoder) {
-                this.decoder = (Decoder) o;
-            }
-        } catch (ClassNotFoundException cnfe) {
-            getLogger().warn("Unable to find decoder", cnfe);
-        } catch (IllegalAccessException | InstantiationException iae) {
-            getLogger().warn("Unable to construct decoder", iae);
-        }
-
-        this.socket = socket;
-    }
-
-    /**
-     * Constructor for socket and reciever.
-     */
-    public XMLSocketNode(String decoder, Socket socket, Receiver receiver) {
-        try {
-            Class c = Class.forName(decoder);
-            Object o = c.newInstance();
-
-            if (o instanceof Decoder) {
-                this.decoder = (Decoder) o;
-            }
-        } catch (ClassNotFoundException cnfe) {
-            getLogger().warn("Unable to find decoder", cnfe);
-        } catch (IllegalAccessException | InstantiationException iae) {
-            getLogger().warn("Unable to construct decoder", iae);
-        }
-
-        this.socket = socket;
-        this.receiver = receiver;
-    }
-
-    /**
-     * Set the event listener on this node.
-     */
-    public void setListener(SocketNodeEventListener _listener) {
-        listener = _listener;
-    }
-
-    public void run() {
-        Logger remoteLogger;
-        Exception listenerException = null;
-        InputStream is;
-
-        if ((this.receiver == null) || (this.decoder == null)) {
-            listenerException =
-                new Exception(
-                    "No receiver or decoder provided.  Cannot process xml socket events");
-            getLogger().error(
-                "Exception constructing XML Socket Receiver", listenerException);
-        }
-
-        try {
-            is = socket.getInputStream();
-        } catch (Exception e) {
-            is = null;
-            listenerException = e;
-            getLogger().error("Exception opening InputStream to " + socket, e);
-        }
-
-        if (is != null) {
-            String hostName = socket.getInetAddress().getHostName();
-            String remoteInfo = hostName + ":" + socket.getPort();
-
-            try {
-                //read data from the socket
-                //it's up to the individual decoder to handle incomplete event data
-                while (true) {
-                    byte[] b = new byte[1024];
-                    int length = is.read(b);
-                    if (length == -1) {
-                        getLogger().info(
-                            "no bytes read from stream - closing connection.");
-                        break;
-                    }
-                    List<LoggingEvent> v = decoder.decodeEvents(new String(b, 0, length));
-
-                    if (v != null) {
-
-                        for (Object aV : v) {
-                            LoggingEvent e = (LoggingEvent) aV;
-                            e.setProperty(Constants.HOSTNAME_KEY, hostName);
-
-                            // store the known remote info in an event property
-                            e.setProperty("log4j.remoteSourceInfo", remoteInfo);
-
-                            // if configured with a receiver, tell it to post the event
-                            if (receiver != null) {
-                                receiver.doPost(e);
-
-                                // else post it via the hierarchy
-                            } else {
-                                // get a logger from the hierarchy. The name of the logger
-                                // is taken to be the name contained in the event.
-                                remoteLogger = repository.getLogger(e.getLoggerName());
-
-                                //event.logger = remoteLogger;
-                                // apply the logger-level filter
-                                if (
-                                    e.getLevel().isGreaterOrEqual(
-                                        remoteLogger.getEffectiveLevel())) {
-                                    // finally log the event as if was generated locally
-                                    remoteLogger.callAppenders(e);
-                                }
-                            }
-                        }
-                    }
-                }
-            } catch (java.io.EOFException e) {
-                getLogger().info("Caught java.io.EOFException closing connection.");
-                listenerException = e;
-            } catch (java.net.SocketException e) {
-                getLogger().info(
-                    "Caught java.net.SocketException closing connection.");
-                listenerException = e;
-            } catch (IOException e) {
-                getLogger().info("Caught java.io.IOException: " + e);
-                getLogger().info("Closing connection.");
-                listenerException = e;
-            } catch (Exception e) {
-                getLogger().error("Unexpected exception. Closing connection.", e);
-                listenerException = e;
-            }
-        }
-
-        // close the socket
-        try {
-            if (is != null) {
-                is.close();
-            }
-        } catch (Exception e) {
-            //logger.info("Could not close connection.", e);
-        }
-
-        // send event to listener, if configured
-        if (listener != null) {
-            listener.socketClosedEvent(listenerException);
-        }
-    }
-}
+///*
+// * 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.helpers.Constants;
+//import org.apache.log4j.plugins.Receiver;
+//import org.apache.log4j.spi.ComponentBase;
+//import org.apache.log4j.spi.Decoder;
+//import org.apache.log4j.spi.LoggerRepository;
+//import org.apache.log4j.spi.LoggingEvent;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.net.Socket;
+//import java.util.List;
+//
+//
+///**
+// * Read {@link LoggingEvent} objects sent from a remote client using XML over
+// * Sockets (TCP). These logging events are logged according to local
+// * policy, as if they were generated locally.
+// * <p>
+// * <p>For example, the socket node might decide to log events to a
+// * local file and also resent them to a second socket node.
+// *
+// * @author Scott Deboy &lt;sdeboy@apache.org&gt;;
+// * @since 0.8.4
+// */
+//public class XMLSocketNode extends ComponentBase implements Runnable {
+//    Socket socket;
+//    Receiver receiver;
+//    Decoder decoder;
+//    SocketNodeEventListener listener;
+//
+//    /**
+//     * Constructor for socket and logger repository.
+//     */
+//    public XMLSocketNode(
+//        String decoder, Socket socket, LoggerRepository hierarchy) {
+//        this.repository = hierarchy;
+//        try {
+//            Class c = Class.forName(decoder);
+//            Object o = c.newInstance();
+//
+//            if (o instanceof Decoder) {
+//                this.decoder = (Decoder) o;
+//            }
+//        } catch (ClassNotFoundException cnfe) {
+//            getLogger().warn("Unable to find decoder", cnfe);
+//        } catch (IllegalAccessException | InstantiationException iae) {
+//            getLogger().warn("Unable to construct decoder", iae);
+//        }
+//
+//        this.socket = socket;
+//    }
+//
+//    /**
+//     * Constructor for socket and reciever.
+//     */
+//    public XMLSocketNode(String decoder, Socket socket, Receiver receiver) {
+//        try {
+//            Class c = Class.forName(decoder);
+//            Object o = c.newInstance();
+//
+//            if (o instanceof Decoder) {
+//                this.decoder = (Decoder) o;
+//            }
+//        } catch (ClassNotFoundException cnfe) {
+//            getLogger().warn("Unable to find decoder", cnfe);
+//        } catch (IllegalAccessException | InstantiationException iae) {
+//            getLogger().warn("Unable to construct decoder", iae);
+//        }
+//
+//        this.socket = socket;
+//        this.receiver = receiver;
+//    }
+//
+//    /**
+//     * Set the event listener on this node.
+//     */
+//    public void setListener(SocketNodeEventListener _listener) {
+//        listener = _listener;
+//    }
+//
+//    public void run() {
+//        Logger remoteLogger;
+//        Exception listenerException = null;
+//        InputStream is;
+//
+//        if ((this.receiver == null) || (this.decoder == null)) {
+//            listenerException =
+//                new Exception(
+//                    "No receiver or decoder provided.  Cannot process xml socket events");
+//            getLogger().error(
+//                "Exception constructing XML Socket Receiver", listenerException);
+//        }
+//
+//        try {
+//            is = socket.getInputStream();
+//        } catch (Exception e) {
+//            is = null;
+//            listenerException = e;
+//            getLogger().error("Exception opening InputStream to " + socket, e);
+//        }
+//
+//        if (is != null) {
+//            String hostName = socket.getInetAddress().getHostName();
+//            String remoteInfo = hostName + ":" + socket.getPort();
+//
+//            try {
+//                //read data from the socket
+//                //it's up to the individual decoder to handle incomplete event data
+//                while (true) {
+//                    byte[] b = new byte[1024];
+//                    int length = is.read(b);
+//                    if (length == -1) {
+//                        getLogger().info(
+//                            "no bytes read from stream - closing connection.");
+//                        break;
+//                    }
+//                    List<LoggingEvent> v = decoder.decodeEvents(new String(b, 0, length));
+//
+//                    if (v != null) {
+//
+//                        for (Object aV : v) {
+//                            LoggingEvent e = (LoggingEvent) aV;
+//                            e.setProperty(Constants.HOSTNAME_KEY, hostName);
+//
+//                            // store the known remote info in an event property
+//                            e.setProperty("log4j.remoteSourceInfo", remoteInfo);
+//
+//                            // if configured with a receiver, tell it to post the event
+//                            if (receiver != null) {
+//                                receiver.doPost(e);
+//
+//                                // else post it via the hierarchy
+//                            } else {
+//                                // get a logger from the hierarchy. The name of the logger
+//                                // is taken to be the name contained in the event.
+//                                remoteLogger = repository.getLogger(e.getLoggerName());
+//
+//                                //event.logger = remoteLogger;
+//                                // apply the logger-level filter
+//                                if (
+//                                    e.getLevel().isGreaterOrEqual(
+//                                        remoteLogger.getEffectiveLevel())) {
+//                                    // finally log the event as if was generated locally
+//                                    remoteLogger.callAppenders(e);
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            } catch (java.io.EOFException e) {
+//                getLogger().info("Caught java.io.EOFException closing connection.");
+//                listenerException = e;
+//            } catch (java.net.SocketException e) {
+//                getLogger().info(
+//                    "Caught java.net.SocketException closing connection.");
+//                listenerException = e;
+//            } catch (IOException e) {
+//                getLogger().info("Caught java.io.IOException: " + e);
+//                getLogger().info("Closing connection.");
+//                listenerException = e;
+//            } catch (Exception e) {
+//                getLogger().error("Unexpected exception. Closing connection.", e);
+//                listenerException = e;
+//            }
+//        }
+//
+//        // close the socket
+//        try {
+//            if (is != null) {
+//                is.close();
+//            }
+//        } catch (Exception e) {
+//            //logger.info("Could not close connection.", e);
+//        }
+//
+//        // send event to listener, if configured
+//        if (listener != null) {
+//            listener.socketClosedEvent(listenerException);
+//        }
+//    }
+//}
diff --git a/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
index eadea44..fe2edd3 100644
--- a/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
+++ b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
@@ -17,6 +17,7 @@
 
 package org.apache.log4j.net;
 
+import java.io.InputStream;
 import org.apache.log4j.plugins.Pauseable;
 import org.apache.log4j.plugins.Plugin;
 import org.apache.log4j.plugins.Receiver;
@@ -27,6 +28,11 @@
 import java.net.Socket;
 import java.util.List;
 import java.util.Vector;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.log4j.spi.Decoder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 
 /**
@@ -49,8 +55,7 @@
  * @author Mark Womack
  * @author Scott Deboy &lt;sdeboy@apache.org&gt;
  */
-public class XMLSocketReceiver extends Receiver implements Runnable, PortBased, Pauseable {
-    private boolean paused;
+public class XMLSocketReceiver extends ChainsawReceiverSkeleton implements Runnable, PortBased {
     //default to log4j xml decoder
     protected String decoder = "org.apache.log4j.xml.XMLDecoder";
     private ServerSocket serverSocket;
@@ -60,6 +65,9 @@
     protected int port = DEFAULT_PORT;
     private boolean advertiseViaMulticastDNS;
     private ZeroConfSupport zeroConf;
+    private boolean active = false;
+
+    private static final Logger logger = LogManager.getLogger();
 
     /**
      * The MulticastDNS zone advertised by an XMLSocketReceiver
@@ -74,15 +82,6 @@
     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.
      */
@@ -108,49 +107,6 @@
         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 XMLSocketReceiver with the current options.
      */
@@ -181,6 +137,7 @@
      * Called when the receiver should be stopped. Closes the
      * server socket and all of the open sockets.
      */
+    @Override
     public synchronized void shutdown() {
         // mark this as no longer running
         active = false;
@@ -199,14 +156,11 @@
     private synchronized void doShutdown() {
         active = false;
 
-        getLogger().debug("{} doShutdown called", getName());
+        logger.debug("{} doShutdown called", getName());
 
         // close the server socket
         closeServerSocket();
 
-        // close all of the accepted sockets
-        closeAllAcceptedSockets();
-
         if (advertiseViaMulticastDNS) {
             zeroConf.unadvertise();
         }
@@ -216,7 +170,7 @@
      * Closes the server socket, if created.
      */
     private void closeServerSocket() {
-        getLogger().debug("{} closing server socket", getName());
+        logger.debug("{} closing server socket", getName());
 
         try {
             if (serverSocket != null) {
@@ -230,39 +184,22 @@
     }
 
     /**
-     * Closes all the connected sockets in the List.
-     */
-    private synchronized void closeAllAcceptedSockets() {
-        for (Object aSocketList : socketList) {
-            try {
-                ((Socket) aSocketList).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);
+        logger.debug("performing socket cleanup prior to entering loop for {}", name);
         closeServerSocket();
-        closeAllAcceptedSockets();
-        getLogger().debug("socket cleanup complete for {}", name);
+        logger.debug("socket cleanup complete for {}", name);
         active = true;
 
         // start the server socket
         try {
             serverSocket = new ServerSocket(port);
         } catch (Exception e) {
-            getLogger().error(
+            logger.error(
                 "error starting XMLSocketReceiver (" + this.getName()
                     + "), receiver did not start", e);
             active = false;
@@ -274,26 +211,22 @@
         Socket socket = null;
 
         try {
-            getLogger().debug("in run-about to enter while isactiveloop");
+            logger.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();
+                if (socket != null ) {
+                    logger.debug("socket not null - parsing data");
+                    parseIncomingData(socket);
                 }
 
-                getLogger().debug("waiting to accept socket");
+                logger.debug("waiting to accept socket");
 
                 // wait for a socket to open, then loop to start it
                 socket = serverSocket.accept();
-                getLogger().debug("accepted socket");
+                logger.debug("accepted socket");
             }
 
             // socket not watched because we a no longer running
@@ -302,19 +235,79 @@
                 socket.close();
             }
         } catch (Exception e) {
-            getLogger().warn(
+            logger.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);
+    @Override
+    public void start() {
+        logger.debug("Starting receiver");
+        if (!isActive()) {
+            rThread = new Thread(this);
+            rThread.setDaemon(true);
+            rThread.start();
+
+            if (advertiseViaMulticastDNS) {
+                zeroConf = new ZeroConfSupport(ZONE, port, getName());
+                zeroConf.advertise();
+            }
+
+            active = true;
         }
     }
 
+    @Override
+    public boolean isActive() {
+        return active;
+    }
 
+    private void parseIncomingData(Socket sock){
+        InputStream is;
+        Decoder d = null;
+        
+        try{
+            d = (Decoder) Class.forName(decoder).getDeclaredConstructor().newInstance();
+        } catch (Exception e) {
+            logger.error("Unable to load correct decoder", e);
+            return;
+        }
+
+        try {
+            is = sock.getInputStream();
+        } catch (Exception e) {
+            is = null;
+            logger.error("Exception opening InputStream to " + sock, e);
+            return;
+        }
+
+        while (is != null) {
+            try{
+                byte[] b = new byte[1024];
+                int length = is.read(b);
+                if (length == -1) {
+                    logger.info(
+                        "no bytes read from stream - closing connection.");
+                    break;
+                }
+                List<ChainsawLoggingEvent> v = d.decodeEvents(new String(b, 0, length));
+
+                for( ChainsawLoggingEvent evt : v ){
+                    append(evt);
+                }
+            }catch(Exception ex){
+                logger.error(ex);
+                break;
+            }
+        }
+
+        // close the socket
+        try {
+            if (is != null) {
+                is.close();
+            }
+        } catch (Exception e) {
+            //logger.info("Could not close connection.", e);
+        }
+    }
 }
diff --git a/src/main/java/org/apache/log4j/spi/Decoder.java b/src/main/java/org/apache/log4j/spi/Decoder.java
index 6965105..5d3cb15 100644
--- a/src/main/java/org/apache/log4j/spi/Decoder.java
+++ b/src/main/java/org/apache/log4j/spi/Decoder.java
@@ -22,6 +22,7 @@
 import java.net.URL;
 import java.util.Map;
 import java.util.Vector;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
 
 
 /**
@@ -37,7 +38,7 @@
      * @param document document to decode.
      * @return list of LoggingEvent instances.
      */
-    Vector<LoggingEvent> decodeEvents(String document);
+    Vector<ChainsawLoggingEvent> decodeEvents(String document);
 
     /**
      * Decode event from string.
@@ -45,7 +46,7 @@
      * @param event string representation of event
      * @return event
      */
-    LoggingEvent decode(String event);
+    ChainsawLoggingEvent decode(String event);
 
     /**
      * Decode event from document retreived from URL.
@@ -54,7 +55,7 @@
      * @return list of LoggingEvent instances.
      * @throws IOException if IO error resolving document.
      */
-    Vector<LoggingEvent> decode(URL url) throws IOException;
+    Vector<ChainsawLoggingEvent> decode(URL url) throws IOException;
 
     /**
      * Sets additional properties.
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index a777fba..773c644 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -17,25 +17,28 @@
 
 package org.apache.log4j.varia;
 
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.log4j.helpers.Constants;
 import org.apache.log4j.plugins.Receiver;
 import org.apache.log4j.rule.ExpressionRule;
 import org.apache.log4j.rule.Rule;
-import org.apache.log4j.spi.LocationInfo;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.ThrowableInformation;
 
 import java.io.*;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
 import java.util.*;
 import java.util.regex.MatchResult;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
+import org.apache.log4j.chainsaw.logevents.Level;
+import org.apache.log4j.chainsaw.logevents.LocationInfo;
+import org.apache.logging.log4j.LogManager;
 
 /**
  * LogFilePatternReceiver can parse and tail log files, converting entries into
@@ -127,7 +130,7 @@
  *
  * @author Scott Deboy
  */
-public class LogFilePatternReceiver extends Receiver {
+public class LogFilePatternReceiver extends ChainsawReceiverSkeleton {
     private final List<String> keywords = new ArrayList<>();
 
     private static final String PROP_START = "PROP(";
@@ -197,6 +200,12 @@
     //default to one line - this number is incremented for each (NL) found in the logFormat
     private int lineCount = 1;
 
+    protected boolean active = false;
+
+    private ChainsawLoggingEventBuilder build = new ChainsawLoggingEventBuilder();
+
+    private static final org.apache.logging.log4j.Logger logger = LogManager.getLogger();
+
     public LogFilePatternReceiver() {
         keywords.add(TIMESTAMP);
         keywords.add(LOGGER);
@@ -475,11 +484,11 @@
      *
      * @return event
      */
-    private LoggingEvent buildEvent() {
+    private ChainsawLoggingEvent buildEvent() {
         if (currentMap.size() == 0) {
             if (additionalLines.size() > 0) {
                 for (Object additionalLine : additionalLines) {
-                    getLogger().debug("found non-matching line: " + additionalLine);
+                    logger.debug("found non-matching line: " + additionalLine);
                 }
             }
             additionalLines.clear();
@@ -494,7 +503,7 @@
             currentMap.put(MESSAGE, buildMessage((String) currentMap.get(MESSAGE),
                 exceptionLine));
         }
-        LoggingEvent event = convertToEvent(currentMap, exception);
+        ChainsawLoggingEvent event = convertToEvent(currentMap, exception);
         currentMap.clear();
         additionalLines.clear();
         return event;
@@ -531,10 +540,10 @@
             exceptionMatcher = exceptionPattern.matcher(input);
             if (eventMatcher.matches()) {
                 //build an event from the previous match (held in current map)
-                LoggingEvent event = buildEvent();
+                ChainsawLoggingEvent event = buildEvent();
                 if (event != null) {
                     if (passesExpression(event)) {
-                        doPost(event);
+                        append(event);
                     }
                 }
                 currentMap.putAll(processEvent(eventMatcher.toMatchResult()));
@@ -551,10 +560,10 @@
                     String lastTime = (String) currentMap.get(TIMESTAMP);
                     //build an event from the previous match (held in current map)
                     if (currentMap.size() > 0) {
-                        LoggingEvent event = buildEvent();
+                        ChainsawLoggingEvent event = buildEvent();
                         if (event != null) {
                             if (passesExpression(event)) {
-                                doPost(event);
+                                append(event);
                             }
                         }
                     }
@@ -569,10 +578,10 @@
         }
 
         //process last event if one exists
-        LoggingEvent event = buildEvent();
+        ChainsawLoggingEvent event = buildEvent();
         if (event != null) {
             if (passesExpression(event)) {
-                doPost(event);
+                append(event);
             }
         }
     }
@@ -587,7 +596,7 @@
      * @param event
      * @return true if expression isn't set, or the result of the evaluation otherwise
      */
-    private boolean passesExpression(LoggingEvent event) {
+    private boolean passesExpression(ChainsawLoggingEvent event) {
         if (event != null) {
             if (expressionRule != null) {
 //                return (expressionRule.evaluate(event, null));
@@ -683,7 +692,7 @@
                 expressionRule = ExpressionRule.getRule(filterExpression);
             }
         } catch (Exception e) {
-            getLogger().warn("Invalid filter expression: " + filterExpression, e);
+            logger.warn("Invalid filter expression: " + filterExpression, e);
         }
 
         List<String> buildingKeywords = new ArrayList<>();
@@ -782,7 +791,7 @@
         }
 
         regexp = newPattern;
-        getLogger().debug("regexp is " + regexp);
+        logger.debug("regexp is " + regexp);
     }
 
     private void updateCustomLevelDefinitionMap() {
@@ -792,7 +801,7 @@
             customLevelDefinitionMap.clear();
             while (entryTokenizer.hasMoreTokens()) {
                 StringTokenizer innerTokenizer = new StringTokenizer(entryTokenizer.nextToken(), "=");
-                customLevelDefinitionMap.put(innerTokenizer.nextToken(), Level.toLevel(innerTokenizer.nextToken()));
+//                customLevelDefinitionMap.put(innerTokenizer.nextToken(), Level.toLevel(innerTokenizer.nextToken()));
             }
         }
     }
@@ -836,7 +845,7 @@
         int propLength = oldString.length();
         int startPos = inputString.indexOf(oldString);
         if (startPos == -1) {
-            getLogger().info("string: " + oldString + " not found in input: " + inputString + " - returning input");
+            logger.info("string: " + oldString + " not found in input: " + inputString + " - returning input");
             return inputString;
         }
         if (startPos == 0) {
@@ -891,7 +900,7 @@
      * @param exception
      * @return logging event
      */
-    private LoggingEvent convertToEvent(Map fieldMap, String[] exception) {
+    private ChainsawLoggingEvent convertToEvent(Map fieldMap, String[] exception) {
         if (fieldMap == null) {
             return null;
         }
@@ -904,11 +913,11 @@
             exception = emptyException;
         }
 
-        Logger logger;
+        String logger;
         long timeStamp = 0L;
         String level;
         String threadName;
-        Object message;
+        String message;
         String ndc;
         String className;
         String methodName;
@@ -916,7 +925,7 @@
         String lineNumber;
         Hashtable properties = new Hashtable();
 
-        logger = Logger.getLogger((String) fieldMap.remove(LOGGER));
+        logger = (String) fieldMap.remove(LOGGER);
 
         if ((dateFormat != null) && fieldMap.containsKey(TIMESTAMP)) {
             try {
@@ -931,31 +940,31 @@
             timeStamp = System.currentTimeMillis();
         }
 
-        message = fieldMap.remove(MESSAGE);
+        message = (String)fieldMap.remove(MESSAGE);
         if (message == null) {
             message = "";
         }
 
         level = (String) fieldMap.remove(LEVEL);
-        Level levelImpl;
-        if (level == null) {
-            levelImpl = Level.DEBUG;
-        } else {
-            //first try to resolve against custom level definition map, then fall back to regular levels
-            levelImpl = customLevelDefinitionMap.get(level);
-            if (levelImpl == null) {
-                levelImpl = Level.toLevel(level.trim());
-                if (!level.equals(levelImpl.toString())) {
-                    //check custom level map
-                    if (levelImpl == null) {
-                        levelImpl = Level.DEBUG;
-                        getLogger().debug("found unexpected level: " + level + ", logger: " + logger.getName() + ", msg: " + message);
-                        //make sure the text that couldn't match a level is added to the message
-                        message = level + " " + message;
-                    }
-                }
-            }
-        }
+//        Level levelImpl;
+//        if (level == null) {
+//            levelImpl = Level.DEBUG;
+//        } else {
+//            //first try to resolve against custom level definition map, then fall back to regular levels
+//            levelImpl = customLevelDefinitionMap.get(level);
+//            if (levelImpl == null) {
+//                levelImpl = Level.toLevel(level.trim());
+//                if (!level.equals(levelImpl.toString())) {
+//                    //check custom level map
+//                    if (levelImpl == null) {
+//                        levelImpl = Level.DEBUG;
+//                        logger.debug("found unexpected level: " + level + ", logger: " + logger.getName() + ", msg: " + message);
+//                        //make sure the text that couldn't match a level is added to the message
+//                        message = level + " " + message;
+//                    }
+//                }
+//            }
+//        }
 
         threadName = (String) fieldMap.remove(THREAD);
 
@@ -979,24 +988,25 @@
         //all remaining entries in fieldmap are properties
         properties.putAll(fieldMap);
 
-        LocationInfo info;
+        LocationInfo info = null;
 
         if ((eventFileName != null) || (className != null) || (methodName != null)
             || (lineNumber != null)) {
-            info = new LocationInfo(eventFileName, className, methodName, lineNumber);
-        } else {
-            info = LocationInfo.NA_LOCATION_INFO;
+            info = new LocationInfo(eventFileName, className, methodName, 
+                    Integer.parseInt(lineNumber));
         }
 
-        LoggingEvent event = new LoggingEvent(null,
-            logger, timeStamp, levelImpl, message,
-            threadName,
-            new ThrowableInformation(exception),
-            ndc,
-            info,
-            properties);
+        build.clear();
+        build.setLogger(logger)
+                .setTimestamp(Instant.ofEpochMilli(timeStamp))
+                .setLevelFromString(level)
+                .setMessage(message)
+                .setThreadName(threadName)
+                .setLocationInfo(info)
+                .setNDC(ndc)
+                .setMDC(properties);
 
-        return event;
+        return build.create();
     }
 
 //  public static void main(String[] args) {
@@ -1018,8 +1028,9 @@
     /**
      * Close the reader.
      */
+    @Override
     public void shutdown() {
-        getLogger().info(getPath() + " shutdown");
+        logger.info(getPath() + " shutdown");
         active = false;
         try {
             if (reader != null) {
@@ -1034,18 +1045,19 @@
     /**
      * Read and process the log file.
      */
-    public void activateOptions() {
-        getLogger().info("activateOptions");
+    @Override
+    public void start() {
+        logger.info("activateOptions");
         active = true;
         Runnable runnable = new Runnable() {
             public void run() {
                 initialize();
                 while (reader == null) {
-                    getLogger().info("attempting to load file: " + getFileURL());
+                    logger.info("attempting to load file: " + getFileURL());
                     try {
                         reader = new InputStreamReader(new URL(getFileURL()).openStream(), "UTF-8");
                     } catch (FileNotFoundException fnfe) {
-                        getLogger().info("file not available - will try again");
+                        logger.info("file not available - will try again");
                         synchronized (this) {
                             try {
                                 wait(MISSING_FILE_RETRY_MILLIS);
@@ -1053,7 +1065,7 @@
                             }
                         }
                     } catch (IOException ioe) {
-                        getLogger().warn("unable to load file", ioe);
+                        logger.warn("unable to load file", ioe);
                         return;
                     }
                 }
@@ -1069,15 +1081,15 @@
                         } catch (InterruptedException ie) {
                         }
                         if (tailing) {
-                            getLogger().debug("tailing file");
+                            logger.debug("tailing file");
                         }
                     } while (tailing);
 
                 } catch (IOException ioe) {
                     //io exception - probably shut down
-                    getLogger().info("stream closed");
+                    logger.info("stream closed");
                 }
-                getLogger().debug("processing " + path + " complete");
+                logger.debug("processing " + path + " complete");
                 shutdown();
             }
         };
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverFactory.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverFactory.java
new file mode 100644
index 0000000..60af991
--- /dev/null
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.varia;
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
+
+/**
+ *
+ */
+public class LogFilePatternReceiverFactory implements ChainsawReceiverFactory {
+
+    @Override
+    public ChainsawReceiver create() {
+        return new LogFilePatternReceiver();
+    }
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException {
+        return new PropertyDescriptor[]{
+            new PropertyDescriptor("name", LogFilePatternReceiver.class),
+            new PropertyDescriptor("fileURL", LogFilePatternReceiver.class),
+            new PropertyDescriptor("appendNonMatches", LogFilePatternReceiver.class),
+            new PropertyDescriptor("filterExpression", LogFilePatternReceiver.class),
+            new PropertyDescriptor("tailing", LogFilePatternReceiver.class),
+            new PropertyDescriptor("logFormat", LogFilePatternReceiver.class),
+            new PropertyDescriptor("group", LogFilePatternReceiver.class),
+            new PropertyDescriptor("timestampFormat", LogFilePatternReceiver.class),
+            new PropertyDescriptor("waitMillis", LogFilePatternReceiver.class),
+        };
+    }
+
+    @Override
+    public String getReceiverName() {
+        return "LogFilePatternReceiver";
+    }
+}
diff --git a/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java b/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
index 12a814d..8011c9d 100644
--- a/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
+++ b/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
@@ -28,6 +28,10 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Collection;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * LogFileXMLReceiver will read an xml-formated log file and make the events in the log file
@@ -55,7 +59,7 @@
  * @since 1.3
  */
 
-public class LogFileXMLReceiver extends Receiver {
+public class LogFileXMLReceiver extends ChainsawReceiverSkeleton {
     private String fileURL;
     private Rule expressionRule;
     private String filterExpression;
@@ -69,6 +73,8 @@
     private String path;
     private boolean useCurrentThread;
 
+    private static final Logger logger = LogManager.getLogger();
+
     /**
      * Accessor
      *
@@ -143,10 +149,10 @@
         this.filterExpression = filterExpression;
     }
 
-    private boolean passesExpression(LoggingEvent event) {
+    private boolean passesExpression(ChainsawLoggingEvent event) {
         if (event != null) {
             if (expressionRule != null) {
-//                return (expressionRule.evaluate(event, null));
+                return (expressionRule.evaluate(event, null));
             }
         }
         return true;
@@ -174,67 +180,10 @@
         }
     }
 
-    /**
-     * Process the file
-     */
-    public void activateOptions() {
-        Runnable runnable = () -> {
-            try {
-                URL url = new URL(fileURL);
-                host = url.getHost();
-                if (host != null && host.equals("")) {
-                    host = FILE_KEY;
-                }
-                path = url.getPath();
-            } catch (MalformedURLException e1) {
-                // TODO Auto-generated catch block
-                e1.printStackTrace();
-            }
-
-            try {
-                if (filterExpression != null) {
-                    expressionRule = ExpressionRule.getRule(filterExpression);
-                }
-            } catch (Exception e) {
-                getLogger().warn("Invalid filter expression: " + filterExpression, e);
-            }
-
-            Class c;
-            try {
-                c = Class.forName(decoder);
-                Object o = c.newInstance();
-                if (o instanceof Decoder) {
-                    decoderInstance = (Decoder) o;
-                }
-            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-            }
-
-            try {
-                reader = new InputStreamReader(new URL(getFileURL()).openStream());
-                process(reader);
-            } catch (FileNotFoundException fnfe) {
-                getLogger().info("file not available");
-            } catch (IOException ioe) {
-                getLogger().warn("unable to load file", ioe);
-                return;
-            }
-        };
-        if (useCurrentThread) {
-            runnable.run();
-        } else {
-            Thread thread = new Thread(runnable, "LogFileXMLReceiver-" + getName());
-
-            thread.start();
-
-        }
-    }
-
     private void process(Reader unbufferedReader) throws IOException {
         BufferedReader bufferedReader = new BufferedReader(unbufferedReader);
         char[] content = new char[10000];
-        getLogger().debug("processing starting: " + fileURL);
+        logger.debug("processing starting: " + fileURL);
         int length;
         do {
             System.out.println("in do loop-about to process");
@@ -250,18 +199,17 @@
                 }
             }
         } while (tailing);
-        getLogger().debug("processing complete: " + fileURL);
+        logger.debug("processing complete: " + fileURL);
 
         shutdown();
     }
 
-    private void processEvents(Collection<LoggingEvent> c) {
+    private void processEvents(Collection<ChainsawLoggingEvent> c) {
         if (c == null) {
             return;
         }
 
-        for (Object aC : c) {
-            LoggingEvent evt = (LoggingEvent) aC;
+        for (ChainsawLoggingEvent evt : c) {
             if (passesExpression(evt)) {
                 if (evt.getProperty(Constants.HOSTNAME_KEY) != null) {
                     evt.setProperty(Constants.HOSTNAME_KEY, host);
@@ -269,7 +217,7 @@
                 if (evt.getProperty(Constants.APPLICATION_KEY) != null) {
                     evt.setProperty(Constants.APPLICATION_KEY, path);
                 }
-                doPost(evt);
+                append(evt);
             }
         }
     }
@@ -294,4 +242,59 @@
         this.useCurrentThread = useCurrentThread;
     }
 
+    @Override
+    public void start() {
+        Runnable runnable = () -> {
+            try {
+                URL url = new URL(fileURL);
+                host = url.getHost();
+                if (host != null && host.equals("")) {
+                    host = FILE_KEY;
+                }
+                path = url.getPath();
+            } catch (MalformedURLException e1) {
+                // TODO Auto-generated catch block
+                e1.printStackTrace();
+            }
+
+            try {
+                if (filterExpression != null) {
+                    expressionRule = ExpressionRule.getRule(filterExpression);
+                }
+            } catch (Exception e) {
+                logger.warn("Invalid filter expression: " + filterExpression, e);
+            }
+
+            Class c;
+            try {
+                c = Class.forName(decoder);
+                Object o = c.newInstance();
+                if (o instanceof Decoder) {
+                    decoderInstance = (Decoder) o;
+                }
+            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+            try {
+                reader = new InputStreamReader(new URL(getFileURL()).openStream());
+                process(reader);
+            } catch (FileNotFoundException fnfe) {
+                logger.info("file not available");
+            } catch (IOException ioe) {
+                logger.warn("unable to load file", ioe);
+                return;
+            }
+        };
+        if (useCurrentThread) {
+            runnable.run();
+        } else {
+            Thread thread = new Thread(runnable, "LogFileXMLReceiver-" + getName());
+
+            thread.start();
+
+        }
+    }
+
 }
diff --git a/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
index 3190b1a..519583d 100644
--- a/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
+++ b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
@@ -17,12 +17,8 @@
 
 package org.apache.log4j.xml;
 
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.log4j.helpers.UtilLoggingLevel;
 import org.apache.log4j.spi.Decoder;
-import org.apache.log4j.spi.LocationInfo;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.ThrowableInformation;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -36,8 +32,12 @@
 import java.awt.*;
 import java.io.*;
 import java.net.URL;
+import java.time.Instant;
 import java.util.*;
 import java.util.zip.ZipInputStream;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
+import org.apache.log4j.chainsaw.logevents.LocationInfo;
 
 
 /**
@@ -80,6 +80,8 @@
      */
     private Component owner = null;
 
+    private ChainsawLoggingEventBuilder builder = new ChainsawLoggingEventBuilder();
+
     private static final String ENCODING = "UTF-8";
 
     /**
@@ -173,7 +175,7 @@
      * @return Vector of LoggingEvents
      * @throws IOException if IO error during processing.
      */
-    public Vector<LoggingEvent> decode(final URL url) throws IOException {
+    public Vector<ChainsawLoggingEvent> decode(final URL url) throws IOException {
         LineNumberReader reader;
         boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
         InputStream inputStream;
@@ -192,10 +194,10 @@
         } else {
             reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
         }
-        Vector<LoggingEvent> v = new Vector<>();
+        Vector<ChainsawLoggingEvent> v = new Vector<>();
 
         String line;
-        Vector<LoggingEvent> events;
+        Vector<ChainsawLoggingEvent> events;
         try {
             while ((line = reader.readLine()) != null) {
                 StringBuilder buffer = new StringBuilder(line);
@@ -227,7 +229,7 @@
      * @param document to decode events from
      * @return Vector of LoggingEvents
      */
-    public Vector<LoggingEvent> decodeEvents(final String document) {
+    public Vector<ChainsawLoggingEvent> decodeEvents(final String document) {
 
         if (document != null) {
 
@@ -279,14 +281,14 @@
      * @param data XML fragment
      * @return a single LoggingEvent or null
      */
-    public LoggingEvent decode(final String data) {
+    public ChainsawLoggingEvent decode(final String data) {
         Document document = parse(data);
 
         if (document == null) {
             return null;
         }
 
-        Vector<LoggingEvent> events = decodeEvents(document);
+        Vector<ChainsawLoggingEvent> events = decodeEvents(document);
 
         if (events.size() > 0) {
             return events.firstElement();
@@ -301,8 +303,8 @@
      * @param document XML document
      * @return Vector of LoggingEvents
      */
-    private Vector<LoggingEvent> decodeEvents(final Document document) {
-        Vector<LoggingEvent> events = new Vector<>();
+    private Vector<ChainsawLoggingEvent> decodeEvents(final Document document) {
+        Vector<ChainsawLoggingEvent> events = new Vector<>();
 
         NodeList eventList = document.getElementsByTagName("record");
 
@@ -310,11 +312,11 @@
              eventIndex++) {
             Node eventNode = eventList.item(eventIndex);
 
-            Logger logger = null;
+            String logger = null;
             long timeStamp = 0L;
-            Level level = null;
+            String level = null;
             String threadName = null;
-            Object message = null;
+            String message = null;
             String ndc = null;
             String[] exception = null;
             String className = null;
@@ -336,7 +338,7 @@
                 String tagName = list.item(y).getNodeName();
 
                 if (tagName.equalsIgnoreCase("logger")) {
-                    logger = Logger.getLogger(getCData(list.item(y)));
+                    logger = getCData(list.item(y));
                 }
 
                 if (tagName.equalsIgnoreCase("millis")) {
@@ -344,7 +346,7 @@
                 }
 
                 if (tagName.equalsIgnoreCase("level")) {
-                    level = UtilLoggingLevel.toLevel(getCData(list.item(y)));
+                    level = getCData(list.item(y));
                 }
 
                 if (tagName.equalsIgnoreCase("thread")) {
@@ -415,9 +417,10 @@
                 || (className != null)
                 || (methodName != null)
                 || (lineNumber != null)) {
-                info = new LocationInfo(fileName, className, methodName, lineNumber);
+                info = new LocationInfo(fileName, className, methodName, 
+                        Integer.parseInt(lineNumber));
             } else {
-                info = LocationInfo.NA_LOCATION_INFO;
+                info = null;
             }
 
             ThrowableInformation throwableInfo = null;
@@ -425,15 +428,18 @@
                 throwableInfo = new ThrowableInformation(exception);
             }
 
-            LoggingEvent loggingEvent = new LoggingEvent(null,
-                logger, timeStamp, level, message,
-                threadName,
-                throwableInfo,
-                ndc,
-                info,
-                properties);
+            builder.clear();
+            builder.setLogger(logger)
+                    .setTimestamp(Instant.ofEpochMilli(timeStamp))
+                    .setLevelFromString(level)
+                    .setMessage(message)
+                    .setThreadName(threadName)
+                    .setMDC(properties)
+                    .setNDC(ndc)
+                    .setLocationInfo(info);
 
-            events.add(loggingEvent);
+
+            events.add(builder.create());
 
         }
         return events;
diff --git a/src/main/java/org/apache/log4j/xml/XMLDecoder.java b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
index e2d034d..a747d75 100644
--- a/src/main/java/org/apache/log4j/xml/XMLDecoder.java
+++ b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
@@ -17,11 +17,7 @@
 
 package org.apache.log4j.xml;
 
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
 import org.apache.log4j.spi.Decoder;
-import org.apache.log4j.spi.LocationInfo;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.ThrowableInformation;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -35,11 +31,16 @@
 import java.awt.*;
 import java.io.*;
 import java.net.URL;
+import java.time.Instant;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
 import java.util.Vector;
 import java.util.zip.ZipInputStream;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
+import org.apache.log4j.chainsaw.logevents.Level;
+import org.apache.log4j.chainsaw.logevents.LocationInfo;
 
 
 /**
@@ -97,6 +98,8 @@
      */
     private Component owner = null;
 
+    private ChainsawLoggingEventBuilder builder = new ChainsawLoggingEventBuilder();
+
     /**
      * Create new instance.
      *
@@ -175,7 +178,7 @@
      * @return Vector of LoggingEvents
      * @throws IOException if IO error during processing.
      */
-    public Vector<LoggingEvent> decode(final URL url) throws IOException {
+    public Vector<ChainsawLoggingEvent> decode(final URL url) throws IOException {
         LineNumberReader reader;
         boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
         InputStream inputStream;
@@ -195,10 +198,10 @@
             reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
         }
 
-        Vector<LoggingEvent> v = new Vector<>();
+        Vector<ChainsawLoggingEvent> v = new Vector<>();
 
         String line;
-        Vector<LoggingEvent> events;
+        Vector<ChainsawLoggingEvent> events;
         try {
             while ((line = reader.readLine()) != null) {
                 StringBuilder buffer = new StringBuilder(line);
@@ -230,7 +233,7 @@
      * @param document to decode events from
      * @return Vector of LoggingEvents
      */
-    public Vector<LoggingEvent> decodeEvents(final String document) {
+    public Vector<ChainsawLoggingEvent> decodeEvents(final String document) {
         if (document != null) {
             if (document.trim().equals("")) {
                 return null;
@@ -279,14 +282,14 @@
      * @param data XML fragment
      * @return a single LoggingEvent or null
      */
-    public LoggingEvent decode(final String data) {
+    public ChainsawLoggingEvent decode(final String data) {
         Document document = parse(data);
 
         if (document == null) {
             return null;
         }
 
-        Vector<LoggingEvent> events = decodeEvents(document);
+        Vector<ChainsawLoggingEvent> events = decodeEvents(document);
 
         if (events.size() > 0) {
             return events.firstElement();
@@ -301,14 +304,14 @@
      * @param document XML document
      * @return Vector of LoggingEvents
      */
-    private Vector<LoggingEvent> decodeEvents(final Document document) {
-        Vector<LoggingEvent> events = new Vector<>();
+    private Vector<ChainsawLoggingEvent> decodeEvents(final Document document) {
+        Vector<ChainsawLoggingEvent> events = new Vector<>();
 
-        Logger logger;
+        String logger;
         long timeStamp;
-        Level level;
+        String level;
         String threadName;
-        Object message = null;
+        String message = null;
         String ndc = null;
         String[] exception = null;
         String className = null;
@@ -329,9 +332,9 @@
             if (eventNode.getNodeType() != Node.ELEMENT_NODE) {
                 continue;
             }
-            logger = Logger.getLogger(eventNode.getAttributes().getNamedItem("logger").getNodeValue());
+            logger = eventNode.getAttributes().getNamedItem("logger").getNodeValue();
             timeStamp = Long.parseLong(eventNode.getAttributes().getNamedItem("timestamp").getNodeValue());
-            level = Level.toLevel(eventNode.getAttributes().getNamedItem("level").getNodeValue());
+            level = eventNode.getAttributes().getNamedItem("level").getNodeValue();
             threadName = eventNode.getAttributes().getNamedItem("thread").getNodeValue();
 
             NodeList list = eventNode.getChildNodes();
@@ -431,25 +434,28 @@
                 || (className != null)
                 || (methodName != null)
                 || (lineNumber != null)) {
-                info = new LocationInfo(fileName, className, methodName, lineNumber);
+                info = new LocationInfo(fileName, className, methodName, 
+                        Integer.parseInt(lineNumber));
             } else {
-                info = LocationInfo.NA_LOCATION_INFO;
+                info = null;
             }
             ThrowableInformation throwableInfo = null;
             if (exception != null) {
                 throwableInfo = new ThrowableInformation(exception);
             }
 
-            LoggingEvent loggingEvent = new LoggingEvent(null,
-                logger, timeStamp, level, message,
-                threadName,
-                throwableInfo,
-                ndc,
-                info,
-                properties);
+            builder.clear();
+            builder.setLogger(logger)
+                    .setTimestamp(Instant.ofEpochMilli(timeStamp))
+                    .setLevelFromString(level)
+                    .setMessage(message)
+                    .setThreadName(threadName)
+                    .setMDC(properties)
+                    .setNDC(ndc)
+                    .setLocationInfo(info);
 
 
-            events.add(loggingEvent);
+            events.add(builder.create());
 
             message = null;
             ndc = null;
diff --git a/src/main/resources/META-INF/services/org.apache.log4j.chainsaw.ChainsawReceiverFactory b/src/main/resources/META-INF/services/org.apache.log4j.chainsaw.ChainsawReceiverFactory
index 3ce8aa8..ea467ac 100644
--- a/src/main/resources/META-INF/services/org.apache.log4j.chainsaw.ChainsawReceiverFactory
+++ b/src/main/resources/META-INF/services/org.apache.log4j.chainsaw.ChainsawReceiverFactory
@@ -1 +1,5 @@
+org.apache.log4j.net.MulticastReceiverFactory
+org.apache.log4j.net.UDPReceiverFactory
+org.apache.log4j.net.XMLReceiverFactory
+org.apache.log4j.varia.LogFilePatternReceiverFactory
 org.apache.log4j.net.JsonReceiverFactory
diff --git a/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
index 59cba7f..d053723 100644
--- a/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
+++ b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
@@ -24,6 +24,7 @@
 import java.nio.CharBuffer;
 import java.util.Vector;
 import java.net.URL;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
 
 /**
  * Tests for XMLDecoder.
@@ -58,28 +59,28 @@
     public void testDecodeEventsString1() throws Exception {
         String xmlStr = getStringFromResource("xmlLayout.1.xml", 10000);
         XMLDecoder decoder = new XMLDecoder();
-        Vector<org.apache.log4j.spi.LoggingEvent> events = decoder.decodeEvents(xmlStr);
+        Vector<ChainsawLoggingEvent> events = decoder.decodeEvents(xmlStr);
         assertEquals(17, events.size());
     }
 
   public void testDecodeEventsString2() throws Exception {
       String xmlStr = getStringFromResource("xsltLayout.1.xml", 10000);
       XMLDecoder decoder = new XMLDecoder();
-      Vector<org.apache.log4j.spi.LoggingEvent> events = decoder.decodeEvents(xmlStr);
+      Vector<ChainsawLoggingEvent> events = decoder.decodeEvents(xmlStr);
       assertEquals(15, events.size());
   }
 
     public void testDecodeEventsURL1() throws Exception {
         URL resource = XMLDecoderTest.class.getResource("xmlLayout.1.xml");
         XMLDecoder decoder = new XMLDecoder();
-        Vector<org.apache.log4j.spi.LoggingEvent> events = decoder.decode(resource);
+        Vector<ChainsawLoggingEvent> events = decoder.decode(resource);
         assertEquals(17, events.size());
     }
 
     public void testDecodeEventsURL2() throws Exception {
         URL resource = XMLDecoderTest.class.getResource("xsltLayout.1.xml");
         XMLDecoder decoder = new XMLDecoder();
-        Vector<org.apache.log4j.spi.LoggingEvent> events = decoder.decode(resource);
+        Vector<ChainsawLoggingEvent> events = decoder.decode(resource);
         assertEquals(15, events.size());
     }