Mostly refactored the old Receiver class out with new Chainsaw version
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawAppender.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawAppender.java
index 59618b3..e05bc1b 100755
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawAppender.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawAppender.java
@@ -63,12 +63,16 @@
         m_receiver.append(builder.create());
     }
 
-    public Receiver getReceiver(){
+    public ChainsawReceiver getReceiver(){
         return m_receiver;
     }
 
-    class ChainsawAppenderReceiver extends Receiver {
-        public void shutdown(){}
-        public void activateOptions(){}
+    class ChainsawAppenderReceiver extends ChainsawReceiverSkeleton {
+
+        @Override
+        public void start() {}
+
+        @Override
+        public void shutdown() {}
     }
 }
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java
new file mode 100644
index 0000000..c93521e
--- /dev/null
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiver.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.beans.PropertyChangeListener;
+import org.apache.log4j.chainsaw.logevents.Level;
+
+/**
+ * A receiver receives log events from a source.
+ */
+public interface ChainsawReceiver {
+    
+    public void addChainsawEventBatchListener( ChainsawEventBatchListener listen );
+    
+    public void removeEventBatchListener( ChainsawEventBatchListener listen );
+    
+    public void setThreshold(final Level level);
+    
+    public Level getThreshold();
+    
+    public String getName();
+    
+    public void setName(String name);
+    
+    public int getQueueInterval();
+
+    public void setQueueInterval(int interval);
+    
+    public void setPaused(boolean paused);
+    
+    public boolean getPaused();
+    
+    /**
+     * Start this receiver by(for example) opening a network socket.
+     */
+    public void start();
+    
+    /**
+     * Stop this receiver by(for example) closing network sockets.
+     */
+    public void shutdown();
+    
+    public void addPropertyChangeListener(final PropertyChangeListener listener);
+    
+    public void addPropertyChangeListener(
+        final String propertyName,
+        final PropertyChangeListener listener);
+    
+    public void removePropertyChangeListener(
+        final PropertyChangeListener listener);
+    
+    public void removePropertyChangeListener(
+        final String propertyName,
+        final PropertyChangeListener listener);
+}
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverFactory.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverFactory.java
new file mode 100644
index 0000000..eb46a4a
--- /dev/null
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+
+/**
+ * A factory that will create new instances of Receivers
+ */
+public interface ChainsawReceiverFactory {
+    
+    /**
+     * Create a new ChainsawReceiver from this factory.
+     * @return 
+     */
+    public ChainsawReceiver create();
+    
+    /**
+     * For the type of ChainsawReceiver that this factory creates,
+     * get the property descriptors for the class.
+     * @return 
+     */
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException;
+    
+    /**
+     * Get the name of the receiver that this factory will create
+     * @return 
+     */
+    public String getReceiverName();
+}
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverSkeleton.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverSkeleton.java
new file mode 100644
index 0000000..69daeee
--- /dev/null
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawReceiverSkeleton.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.chainsaw;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent;
+import org.apache.log4j.chainsaw.logevents.Level;
+import org.apache.log4j.plugins.Receiver;
+
+/**
+ *
+ */
+public abstract class ChainsawReceiverSkeleton implements ChainsawReceiver {
+    
+    /**
+     * Name of this plugin.
+     */
+    protected String name = "Receiver";
+
+
+    /**
+     * This is a delegate that does all the PropertyChangeListener
+     * support.
+     */
+    private PropertyChangeSupport propertySupport =
+        new PropertyChangeSupport(this);
+    
+    /**
+     * Threshold level.
+     */
+    protected Level thresholdLevel = Level.TRACE;
+    
+    private List<ChainsawEventBatchListener> m_eventListeners;
+    private WorkQueue m_worker;
+    private final Object mutex = new Object();
+    private int m_sleepInterval = 1000;
+    private boolean m_paused = false;
+    
+    public ChainsawReceiverSkeleton(){
+        m_eventListeners = new ArrayList<>();
+        m_worker = new WorkQueue();
+    }
+
+    @Override
+    public void addChainsawEventBatchListener(ChainsawEventBatchListener listen) {
+        if( listen != null ){
+            m_eventListeners.add( listen );
+        }
+    }
+
+    @Override
+    public void removeEventBatchListener(ChainsawEventBatchListener listen) {
+        if( listen != null ){
+            m_eventListeners.remove( listen );
+        }
+    }
+
+    @Override
+    public void setThreshold(Level level) {
+        Level oldValue = this.thresholdLevel;
+        thresholdLevel = level;
+        propertySupport.firePropertyChange("threshold", oldValue, this.thresholdLevel);
+    }
+
+    @Override
+    public Level getThreshold() {
+        return thresholdLevel;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(listener);
+    }
+
+    @Override
+    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(propertyName, listener);
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(listener);
+    }
+
+    @Override
+    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(propertyName, listener);
+    }
+    
+    @Override
+    public int getQueueInterval() {
+        return m_sleepInterval;
+    }
+
+    @Override
+    public void setQueueInterval(int interval) {
+        m_sleepInterval = interval;
+    }
+    
+    @Override
+    public void setPaused(boolean paused){
+        m_paused = paused;
+    }
+    
+    @Override
+    public boolean getPaused(){
+        return m_paused;
+    }
+    
+    /**
+     * Whenever a new log event comes in, create a ChainsawLoggingEvent and call
+     * this method.  If this receiver is paused, discard the event.
+     * 
+     * @param event 
+     */
+    protected void append(final ChainsawLoggingEvent event){
+        if( m_paused ) return;
+        m_worker.enqueue(event);
+    }
+    
+    /**
+     * Queue of Events are placed in here, which are picked up by an asychronous
+     * thread. The WorkerThread looks for events once a second and processes all
+     * events accumulated during that time..
+     */
+    class WorkQueue {
+        final ArrayList<ChainsawLoggingEvent> queue = new ArrayList<>();
+        Thread workerThread;
+
+        protected WorkQueue() {
+            workerThread = new WorkerThread();
+            workerThread.start();
+        }
+
+        public final void enqueue(ChainsawLoggingEvent event) {
+            synchronized (mutex) {
+                queue.add(event);
+                mutex.notify();
+            }
+        }
+
+        public final void stop() {
+            synchronized (mutex) {
+                workerThread.interrupt();
+            }
+        }
+
+        /**
+         * The worker thread converts each queued event to a vector and forwards the
+         * vector on to the UI.
+         */
+        private class WorkerThread extends Thread {
+            public WorkerThread() {
+                super("Chainsaw-WorkerThread");
+                setDaemon(true);
+                setPriority(Thread.NORM_PRIORITY - 1);
+            }
+
+            public void run() {
+                while (true) {
+                    List<ChainsawLoggingEvent> innerList = new ArrayList<>();
+                    synchronized (mutex) {
+                        try {
+                            while ((queue.size() == 0)) {
+//                                setDataRate(0);
+                                mutex.wait();
+                            }
+                            if (queue.size() > 0) {
+                                innerList.addAll(queue);
+                                queue.clear();
+                            }
+                        } catch (InterruptedException ie) {
+                        }
+                    }
+
+                    for( ChainsawEventBatchListener evtListner : m_eventListeners ){
+                        evtListner.receiveChainsawEventBatch(innerList);
+                    }
+                    
+                    if (getQueueInterval() > 1000) {
+                        try {
+                            synchronized (this) {
+                                wait(getQueueInterval());
+                            }
+                        } catch (InterruptedException ie) {
+                        }
+                    } else {
+                        Thread.yield();
+                    }
+//                    if (size == 0) {
+//                        setDataRate(0.0);
+//                    } else {
+//                        long timeEnd = System.currentTimeMillis();
+//                        long diffInSeconds = (timeEnd - timeStart) / 1000;
+//                        double rate = (((double) size) / diffInSeconds);
+//                        setDataRate(rate);
+//                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index f026ec0..bf78d9f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -181,7 +181,7 @@
     private ColorizedEventAndSearchMatchThumbnail colorizedEventAndSearchMatchThumbnail;
     private EventTimeDeltaMatchThumbnail eventTimeDeltaMatchThumbnail;
     private boolean isDetailPanelVisible;
-    private Receiver m_receiver;
+    private ChainsawReceiver m_receiver;
 
     /**
      * Creates a new LogPanel object.  If a LogPanel with this identifier has
@@ -3035,7 +3035,7 @@
         return selectedItem.toString();
     }
 
-    public void setReceiver( Receiver rx ){
+    public void setReceiver( ChainsawReceiver rx ){
         m_receiver = rx;
         m_receiver.addPropertyChangeListener(((pce) -> {
             if( pce.getPropertyName().equals( "name" ) ){
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 8381886..b00ce7c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1822,7 +1822,7 @@
     }
 
     private void buildLogPanel(
-        boolean customExpression, final String ident, final List<ChainsawLoggingEvent> events, final Receiver rx)
+        boolean customExpression, final String ident, final List<ChainsawLoggingEvent> events, final ChainsawReceiver rx)
         throws IllegalArgumentException {
         final LogPanel thisPanel = new LogPanel(getStatusBar(), ident, cyclicBufferSize, allColorizers, applicationPreferenceModel);
 
@@ -1898,7 +1898,7 @@
         MessageCenter.getInstance().getLogger().debug(msg);
     }
 
-    public void receiverAdded(Receiver rx){
+    public void receiverAdded(ChainsawReceiver rx){
         List<ChainsawLoggingEvent> list = new ArrayList<>();
         buildLogPanel(false, rx.getName(), list, rx);
     }
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index 6a0b736..2e5499c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -36,7 +36,6 @@
 import java.net.URL;
 import java.util.List;
 import java.util.Locale;
-import org.apache.log4j.net.JsonReceiver;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -291,7 +290,7 @@
 
         networkReceiverClassNameComboBoxModel = new DefaultComboBoxModel<>();
         networkReceiverClassNameComboBoxModel.addElement(UDPReceiver.class.getName());
-        networkReceiverClassNameComboBoxModel.addElement(JsonReceiver.class.getName());
+//        networkReceiverClassNameComboBoxModel.addElement(JsonReceiver.class.getName());
 
         networkReceiverClassNameComboBox = new JComboBox<>(networkReceiverClassNameComboBoxModel);
 
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/NewReceiverDialogPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/NewReceiverDialogPanel.java
index 75f1723..000daec 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/NewReceiverDialogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/NewReceiverDialogPanel.java
@@ -27,8 +27,12 @@
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.ActionListener;
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
 import java.io.IOException;
 import java.net.URL;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
 
 
 /**
@@ -120,27 +124,13 @@
      * @return NewReceiverDialogPanel
      * @throws IllegalArgumentException if the specified class is not a Receiver
      */
-    public static NewReceiverDialogPanel create(Class<? extends Receiver> receiverClass) {
+    public static NewReceiverDialogPanel create(ChainsawReceiverFactory recvFact) throws IntrospectionException {
 
-        if (!Receiver.class.isAssignableFrom(receiverClass)) {
-            throw new IllegalArgumentException(receiverClass.getName() +
-                " is not a Receiver");
-        }
-
-        Receiver receiverInstance = null;
-
-        try {
-            receiverInstance = (Receiver) receiverClass.newInstance();
-
-        } catch (Exception e) {
-            LogManager.getLogger(NewReceiverDialogPanel.class).error(
-                "Failed to create a new Receiver instance, this exception is unexpected",
-                e);
-        }
+        ChainsawReceiver recv = recvFact.create();
 
         NewReceiverDialogPanel panel = new NewReceiverDialogPanel();
 
-        panel.pluginEditorPanel.setPlugin(receiverInstance);
+        panel.pluginEditorPanel.setReceiverAndProperties(recv, recvFact.getPropertyDescriptors());
 
         return panel;
     }
@@ -156,9 +146,9 @@
     /**
      *
      */
-    public Receiver getReceiver() {
+    public ChainsawReceiver getReceiver() {
 
-        return (Receiver)this.pluginEditorPanel.getPlugin();
+        return this.pluginEditorPanel.getPlugin();
     }
 
 }
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
index 7d8d95a..0b35d1f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
@@ -22,7 +22,6 @@
 import org.apache.log4j.chainsaw.ChainsawConstants;
 import org.apache.log4j.chainsaw.Generator;
 import org.apache.log4j.chainsaw.helper.TableCellEditorFactory;
-import org.apache.log4j.plugins.Plugin;
 
 import javax.swing.*;
 import javax.swing.table.AbstractTableModel;
@@ -40,6 +39,7 @@
 import java.util.List;
 import javax.swing.event.CellEditorListener;
 import javax.swing.table.TableCellRenderer;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
 
 
 /**
@@ -53,7 +53,7 @@
     private final JScrollPane scrollPane = new JScrollPane();
     private final JTable propertyTable = new JTable();
 
-    private Plugin plugin;
+    private ChainsawReceiver m_receiver;
     private TableModel defaultModel = new DefaultTableModel(
         new String[]{"Property", "Value"}, 1);
 
@@ -65,7 +65,6 @@
     public PluginPropertyEditorPanel() {
         super();
         initComponents();
-        setupListeners();
     }
 
     /**
@@ -85,50 +84,25 @@
     }
 
     /**
-     *
-     */
-    private void setupListeners() {
-        addPropertyChangeListener("plugin", evt -> {
-
-            final Plugin p = (Plugin) evt.getNewValue();
-
-            if (p != null) {
-
-                try {
-
-                    PluginPropertyTableModel model =
-                        new PluginPropertyTableModel(p);
-                    propertyTable.setModel(model);
-                    propertyTable.getColumnModel().getColumn(1)
-                        .setCellEditor(new PluginTableCellEditor());
-                    propertyTable.setEnabled(true);
-                } catch (Throwable e) {
-                    logger.error("Failed to introspect the Plugin", e);
-                }
-            } else {
-                propertyTable.setModel(defaultModel);
-                propertyTable.setEnabled(false);
-            }
-
-        });
-    }
-
-    /**
      * @return Returns the plugin.
      */
-    public final Plugin getPlugin() {
+    public final ChainsawReceiver getPlugin() {
 
-        return plugin;
+        return m_receiver;
     }
 
     /**
      * @param plugin The plugin to set.
      */
-    public final void setPlugin(Plugin plugin) {
-
-        Plugin oldValue = this.plugin;
-        this.plugin = plugin;
-        firePropertyChange("plugin", oldValue, this.plugin);
+    public final void setReceiverAndProperties(ChainsawReceiver plugin, PropertyDescriptor[] descriptors) {
+        this.m_receiver = plugin;
+        
+        PluginPropertyTableModel model =
+            new PluginPropertyTableModel(descriptors);
+        propertyTable.setModel(model);
+        propertyTable.getColumnModel().getColumn(1)
+            .setCellEditor(new PluginTableCellEditor());
+        propertyTable.setEnabled(true);
     }
 
     /**
@@ -196,16 +170,12 @@
     private class PluginPropertyTableModel extends AbstractTableModel {
 
         private final PropertyDescriptor[] descriptors;
-        private final Plugin plugin;
 
-        private PluginPropertyTableModel(Plugin p)
-            throws IntrospectionException {
+        private PluginPropertyTableModel(PropertyDescriptor[] descriptors){
             super();
 
-            BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass());
-
-            List list = new ArrayList(Arrays.asList(
-                beanInfo.getPropertyDescriptors()));
+            List<PropertyDescriptor> list = new ArrayList<>(Arrays.asList(
+                descriptors));
 
             list.sort((o1, o2) -> {
 
@@ -215,8 +185,7 @@
                 return d1.getDisplayName().compareToIgnoreCase(
                     d2.getDisplayName());
             });
-            this.plugin = p;
-            this.descriptors = (PropertyDescriptor[]) list.toArray(
+            this.descriptors = list.toArray(
                 new PropertyDescriptor[0]);
         }
 
@@ -233,7 +202,7 @@
 
                     try {
 
-                        Object object = d.getReadMethod().invoke(plugin);
+                        Object object = d.getReadMethod().invoke(m_receiver);
 
                         if (object != null) {
 
@@ -305,7 +274,7 @@
                         ", value=" + aValue + ", valueClass" + aValue.getClass());
 
                 try {
-                    descriptors[rowIndex].getWriteMethod().invoke(plugin,
+                    descriptors[rowIndex].getWriteMethod().invoke(m_receiver,
                         aValue);
                     fireTableCellUpdated(rowIndex, columnIndex);
                 } catch (IllegalArgumentException e) {
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
index 8c65961..fe388e1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
@@ -50,8 +50,10 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
+import org.apache.log4j.chainsaw.ChainsawReceiver;
 import org.apache.log4j.chainsaw.LogUI;
-import org.apache.log4j.net.JsonReceiver;
+import org.apache.log4j.chainsaw.ChainsawReceiverFactory;
 
 
 /**
@@ -167,9 +169,9 @@
                             && (node.getUserObject() instanceof Plugin)) {
                         Plugin p = (Plugin) node.getUserObject();
                         logger.debug("plugin=" + p);
-                        pluginEditorPanel.setPlugin(p);
+//                        pluginEditorPanel.setPlugin(p);
                     } else {
-                        pluginEditorPanel.setPlugin(null);
+//                        pluginEditorPanel.setPlugin(null);
                     }
                 }
             });
@@ -607,79 +609,54 @@
      */
     class NewReceiverPopupMenu extends JPopupMenu {
         NewReceiverPopupMenu() {
-            try {
-                final List receiverList =
-                    ReceiversHelper.getInstance().getKnownReceiverClasses();
-                String separatorCheck = null;
+            ServiceLoader<ChainsawReceiverFactory> sl = ServiceLoader.load(ChainsawReceiverFactory.class);
+            
+            for( ChainsawReceiverFactory crFactory : sl ){
+                add(
+                    new AbstractAction("New " + crFactory.getReceiverName() + "...") {
+                        public void actionPerformed(ActionEvent e) {
+                            Container container = SwingUtilities.getAncestorOfClass(JFrame.class, ReceiversPanel.this);
+                            final JDialog dialog = new JDialog((JFrame) container, "New " + crFactory.getReceiverName() + "...", true);
 
-                for (Object aReceiverList : receiverList) {
-                    final Class toCreate = (Class) aReceiverList;
-                    Package thePackage = toCreate.getPackage();
-                    final String name =
-                        toCreate.getName().substring(thePackage.getName().length() + 1);
+                            try {
+                                final NewReceiverDialogPanel panel =
+                                    NewReceiverDialogPanel.create(crFactory);
+                                dialog.getContentPane().add(panel);
+                                dialog.pack();
+                                SwingHelper.centerOnScreen(dialog);
 
-                    if (separatorCheck == null) {
-                        separatorCheck = name.substring(0, 1);
-                    } else {
-                        String current = name.substring(0, 1);
+                                /**
+                                 * Make the default button the ok button
+                                 */
+                                dialog.getRootPane().setDefaultButton(panel.getOkPanel().getOkButton());
 
-                        if (!current.equals(separatorCheck)) {
-                            addSeparator();
-                            separatorCheck = current;
-                        }
-                    }
-
-                    add(
-                        new AbstractAction("New " + name + "...") {
-                            public void actionPerformed(ActionEvent e) {
-                                Container container = SwingUtilities.getAncestorOfClass(JFrame.class, ReceiversPanel.this);
-                                final JDialog dialog = new JDialog((JFrame) container, "New " + toCreate.getName() + "...", true);
-
-                                try {
-                                    final NewReceiverDialogPanel panel =
-                                        NewReceiverDialogPanel.create(toCreate);
-                                    dialog.getContentPane().add(panel);
-                                    dialog.pack();
-                                    SwingHelper.centerOnScreen(dialog);
-
-                                    /**
-                                     * Make the default button the ok button
-                                     */
-                                    dialog.getRootPane().setDefaultButton(panel.getOkPanel().getOkButton());
-
-                                    /**
-                                     * Use the standard Cancel metaphor
-                                     */
-                                    SwingHelper.configureCancelForDialog(dialog, panel.getOkPanel().getCancelButton());
+                                /**
+                                 * Use the standard Cancel metaphor
+                                 */
+                                SwingHelper.configureCancelForDialog(dialog, panel.getOkPanel().getCancelButton());
 
 
-                                    panel.getOkPanel().getOkButton().addActionListener(
-                                        e2 -> {
-                                            Receiver receiver = panel.getReceiver();
-                                            if (receiver.getName() != null && !receiver.getName().trim().equals("")) {
-                                                dialog.dispose();
-                                                pluginRegistry.addPlugin(receiver);
-                                                receiver.activateOptions();
-                                                // Notify the LogUI that a new reciever has been created so it can spawn a new tab
-                                                m_parent.receiverAdded(receiver);
-                                                MessageCenter.getInstance().addMessage("Receiver '" + receiver.getName() + "' started");
-                                            } else {
-                                                MessageCenter.getInstance().getLogger().error("Name required to create receiver");
-                                            }
-                                        });
-                                    dialog.setVisible(true);
-                                } catch (Exception e1) {
-                                    e1.printStackTrace();
-                                    MessageCenter.getInstance().getLogger().error(
-                                        "Failed to create the new Receiver dialog", e1);
-                                }
+                                panel.getOkPanel().getOkButton().addActionListener(
+                                    e2 -> {
+                                        ChainsawReceiver receiver = panel.getReceiver();
+                                        if (receiver.getName() != null && !receiver.getName().trim().equals("")) {
+                                            dialog.dispose();
+                                            // Notify the LogUI that a new reciever has been created so it can spawn a new tab
+                                            m_parent.receiverAdded(receiver);
+                                            MessageCenter.getInstance().addMessage("Receiver '" + receiver.getName() + "' started");
+                                        } else {
+                                            MessageCenter.getInstance().getLogger().error("Name required to create receiver");
+                                        }
+                                    });
+                                dialog.setVisible(true);
+                            } catch (Exception e1) {
+                                e1.printStackTrace();
+                                MessageCenter.getInstance().getLogger().error(
+                                    "Failed to create the new Receiver dialog", e1);
                             }
-                        });
+                        }
+                    });
                 }
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw new RuntimeException(e.getMessage());
-            }
         }
     }
 
diff --git a/src/main/java/org/apache/log4j/net/JsonReceiver.java b/src/main/java/org/apache/log4j/net/JsonReceiver.java
index 2561ee0..fd3c742 100644
--- a/src/main/java/org/apache/log4j/net/JsonReceiver.java
+++ b/src/main/java/org/apache/log4j/net/JsonReceiver.java
@@ -16,8 +16,12 @@
  */
 package org.apache.log4j.net;
 
+import com.owlike.genson.Genson;
+import com.owlike.genson.GensonBuilder;
+import java.io.InputStream;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
 import static org.apache.log4j.net.XMLSocketReceiver.ZONE;
@@ -26,6 +30,10 @@
 import org.apache.log4j.plugins.Receiver;
 import org.apache.log4j.spi.LoggerRepository;
 import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.chainsaw.ChainsawReceiverSkeleton;
+import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * The JsonReceiver class receives log events over a TCP socket(as JSON) and
@@ -33,17 +41,16 @@
  *
  * @author Robert Middleton
  */
-public class JsonReceiver extends Receiver implements Runnable, PortBased, Pauseable {
-    private boolean m_paused;
-    //default to log4j xml decoder
-    protected String m_decoder = "org.apache.log4j.xml.XMLDecoder";
+public class JsonReceiver extends ChainsawReceiverSkeleton implements Runnable, PortBased {
     private ServerSocket m_serverSocket;
-    private List<Socket> m_socketList = new Vector<>();
     private Thread m_rxThread;
     public static final int DEFAULT_PORT = 4449;
     protected int m_port = DEFAULT_PORT;
     private boolean m_advertiseViaMulticastDNS;
     private ZeroConfSupport m_zeroConf;
+    private boolean active = true;
+    
+    private static final Logger logger = LogManager.getLogger();
 
     /**
      * The MulticastDNS zone advertised by an XMLSocketReceiver
@@ -53,15 +60,6 @@
     public JsonReceiver() {
     }
 
-    public JsonReceiver(int _port) {
-        m_port = _port;
-    }
-
-    public JsonReceiver(int _port, LoggerRepository _repository) {
-        m_port = _port;
-        repository = _repository;
-    }
-
     @Override
     public void shutdown() {
         // mark this as no longer running
@@ -81,14 +79,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 (m_advertiseViaMulticastDNS) {
             m_zeroConf.unadvertise();
         }
@@ -98,7 +93,7 @@
      * Closes the server socket, if created.
      */
     private void closeServerSocket() {
-        getLogger().debug("{} closing server socket", getName());
+        logger.debug("{} closing server socket", getName());
 
         try {
             if (m_serverSocket != null) {
@@ -111,24 +106,8 @@
         m_serverSocket = null;
     }
 
-    /**
-     * Closes all the connected sockets in the List.
-     */
-    private synchronized void closeAllAcceptedSockets() {
-        for (Socket sock : m_socketList) {
-            try {
-                sock.close();
-            } catch (Exception e) {
-                // ignore for now
-            }
-        }
-
-        // clear member variables
-        m_socketList.clear();
-    }
-
     @Override
-    public void activateOptions() {
+    public void start() {
         if (!isActive()) {
             m_rxThread = new Thread(this);
             m_rxThread.setDaemon(true);
@@ -148,17 +127,16 @@
         /**
          * 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 {
-            m_serverSocket = new ServerSocket(m_port);
+            m_serverSocket = new ServerSocket(m_port, 1);
         } catch (Exception e) {
-            getLogger().error(
+            logger.error(
                 "error starting JsonReceiver (" + this.getName()
                     + "), receiver did not start", e);
             active = false;
@@ -170,26 +148,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 (!m_rxThread.isInterrupted()) {
                 // if we have a socket, start watching it
-                if (socket != null) {
-                    getLogger().debug("socket not null - creating and starting socketnode");
-                    m_socketList.add(socket);
-
-                    JsonSocketNode node = new JsonSocketNode(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 = m_serverSocket.accept();
-                getLogger().debug("accepted socket");
+                logger.debug("accepted socket");
             }
 
             // socket not watched because we a no longer running
@@ -198,7 +172,7 @@
                 socket.close();
             }
         } catch (Exception e) {
-            getLogger().warn(
+            logger.warn(
                 "socket server disconnected, stopping");
         }
     }
@@ -208,26 +182,6 @@
         return m_port;
     }
 
-    @Override
-    public void setPaused(boolean paused) {
-        m_paused = paused;
-    }
-
-    @Override
-    public boolean isPaused() {
-        return m_paused;
-    }
-
-    public boolean isEquivalent(Plugin testPlugin) {
-        if ((testPlugin != null) && testPlugin instanceof JsonReceiver) {
-            JsonReceiver sReceiver = (JsonReceiver) testPlugin;
-
-            return (m_port == sReceiver.getPort() && super.isEquivalent(testPlugin));
-        }
-
-        return false;
-    }
-
     public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
         m_advertiseViaMulticastDNS = advertiseViaMulticastDNS;
     }
@@ -237,9 +191,53 @@
     }
 
     @Override
-    public void doPost(LoggingEvent event) {
-        if (!isPaused()) {
-            super.doPost(event);
+    public boolean isActive() {
+        return active;
+    }
+    
+    private void parseIncomingData(Socket sock){
+        InputStream is;
+        
+        try {
+            is = sock.getInputStream();
+        } catch (Exception e) {
+            is = null;
+            logger.error("Exception opening InputStream to " + sock, e);
+            return;
+        }
+
+        if (is != null) {
+            Genson genson = new GensonBuilder()
+                    .useDateAsTimestamp(true)
+                    .create();
+
+            try {
+                //read data from the socket.
+                // Once we have a full JSON message, parse it
+                ChainsawLoggingEventBuilder build = new ChainsawLoggingEventBuilder();
+                while (true) {
+                    logger.debug( "About to deserialize values" );
+                    Iterator<ECSLogEvent> iter = genson.deserializeValues(is, ECSLogEvent.class);
+                    // Because the socket can be closed, if we don't have anything parsed
+                    // assume that the socket is closed.
+                    if( !iter.hasNext() ) break;
+                    while( iter.hasNext() ){
+                        ECSLogEvent evt = iter.next();
+                        append(evt.toChainsawLoggingEvent(build));
+                    }
+                }
+            } catch (Exception e) {
+                logger.error("Unexpected exception. Closing connection.", e);
+            }
+        }
+
+        // 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/net/JsonReceiverFactory.java b/src/main/java/org/apache/log4j/net/JsonReceiverFactory.java
new file mode 100644
index 0000000..ea0e1bd
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/JsonReceiverFactory.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.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 JsonReceiverFactory implements ChainsawReceiverFactory {
+
+    @Override
+    public ChainsawReceiver create() {
+//        return new JsonReceiver();
+return null;
+    }
+
+    @Override
+    public PropertyDescriptor[] getPropertyDescriptors() throws IntrospectionException {
+        return new PropertyDescriptor[]{
+//                new PropertyDescriptor("name", JsonReceiver.class)
+//                new PropertyDescriptor("address", MulticastReceiver.class),
+//                new PropertyDescriptor("port", MulticastReceiver.class),
+//                new PropertyDescriptor("threshold", MulticastReceiver.class),
+//                new PropertyDescriptor("decoder", MulticastReceiver.class),
+//                new PropertyDescriptor("advertiseViaMulticastDNS", MulticastReceiver.class),
+            };
+    }
+
+    @Override
+    public String getReceiverName() {
+        return "Json Receiver";
+    }
+    
+}
diff --git a/src/main/java/org/apache/log4j/net/JsonSocketNode.java b/src/main/java/org/apache/log4j/net/JsonSocketNode.java
index 55d3a60..17e9024 100644
--- a/src/main/java/org/apache/log4j/net/JsonSocketNode.java
+++ b/src/main/java/org/apache/log4j/net/JsonSocketNode.java
@@ -1,168 +1,158 @@
-/*
- * 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 com.owlike.genson.Genson;
-import com.owlike.genson.GensonBuilder;
-import com.owlike.genson.stream.ObjectReader;
-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.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
-
-
-/**
- * Read {@link LoggingEvent} objects sent from a remote client using JSON over
- * Sockets (TCP). These logging events are logged according to local
- * policy, as if they were generated locally.
- */
-public class JsonSocketNode extends ComponentBase implements Runnable {
-    Socket m_socket;
-    JsonReceiver m_receiver;
-    SocketNodeEventListener m_listener;
-    private List<Byte> m_jsonBuffer;
-
-    /**
-     * Constructor for socket and logger repository.
-     */
-    public JsonSocketNode(
-        Socket socket, LoggerRepository hierarchy) {
-        this.repository = hierarchy;
-
-        this.m_socket = socket;
-    }
-
-    /**
-     * Constructor for socket and reciever.
-     */
-    public JsonSocketNode(Socket socket, JsonReceiver receiver) {
-        this.m_socket = socket;
-        this.m_receiver = receiver;
-    }
-
-    /**
-     * Set the event listener on this node.
-     */
-    public void setListener(SocketNodeEventListener _listener) {
-        m_listener = _listener;
-    }
-
-    public void run() {
-        Logger remoteLogger;
-        Exception listenerException = null;
-        InputStream is;
-
-        if ((this.m_receiver == null) ) {
-            listenerException =
-                new Exception(
-                    "No receiver provided.  Cannot process JSON socket events");
-            getLogger().error(
-                "Exception constructing JSON Socket Receiver", listenerException);
-        }
-
-        m_jsonBuffer = new ArrayList<>( 8192 );
-
-        try {
-            is = m_socket.getInputStream();
-        } catch (Exception e) {
-            is = null;
-            listenerException = e;
-            getLogger().error("Exception opening InputStream to " + m_socket, e);
-        }
-
-        if (is != null) {
-            String hostName = m_socket.getInetAddress().getHostName();
-            String remoteInfo = hostName + ":" + m_socket.getPort();
-            Genson genson = new GensonBuilder()
-                    .useDateAsTimestamp(true)
-                    .create();
-
-            try {
-                //read data from the socket.
-                // Once we have a full JSON message, parse it
-                ChainsawLoggingEventBuilder build = new ChainsawLoggingEventBuilder();
-                while (true) {
-                    getLogger().debug( "About to deserialize values" );
-                    Iterator<ECSLogEvent> iter = genson.deserializeValues(is, ECSLogEvent.class);
-                    // Because the socket can be closed, if we don't have anything parsed
-                    // assume that the socket is closed.
-                    if( !iter.hasNext() ) break;
-                    while( iter.hasNext() ){
-                        ECSLogEvent evt = iter.next();
-                        m_receiver.append(evt.toChainsawLoggingEvent(build));
-//                        LoggingEvent e = evt.toLoggingEvent();
-//                        e.setProperty(Constants.HOSTNAME_KEY, hostName);
+///*
+// * 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.
+// */
 //
-//                        // store the known remote info in an event property
-//                        e.setProperty("log4j.remoteSourceInfo", remoteInfo);
+//package org.apache.log4j.net;
 //
-//                        // if configured with a receiver, tell it to post the event
-//                        if (m_receiver != null) {
-//                            m_receiver.doPost(e);
+//import com.owlike.genson.Genson;
+//import com.owlike.genson.GensonBuilder;
+//import com.owlike.genson.stream.ObjectReader;
+//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;
 //
-//                            // 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());
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.net.Socket;
+//import java.util.ArrayDeque;
+//import java.util.ArrayList;
+//import java.util.Deque;
+//import java.util.Iterator;
+//import java.util.List;
+//import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEventBuilder;
 //
-//                            //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 (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 (m_listener != null) {
-            m_listener.socketClosedEvent(listenerException);
-        }
-    }
-}
+//
+///**
+// * Read {@link LoggingEvent} objects sent from a remote client using JSON over
+// * Sockets (TCP). These logging events are logged according to local
+// * policy, as if they were generated locally.
+// */
+//public class JsonSocketNode implements Runnable {
+//    Socket m_socket;
+//    JsonReceiver m_receiver;
+//    SocketNodeEventListener m_listener;
+//    private List<Byte> m_jsonBuffer;
+//
+//    /**
+//     * Constructor for socket and reciever.
+//     */
+//    public JsonSocketNode(Socket socket, JsonReceiver receiver) {
+//        this.m_socket = socket;
+//        this.m_receiver = receiver;
+//    }
+//
+//    /**
+//     * Set the event listener on this node.
+//     */
+//    public void setListener(SocketNodeEventListener _listener) {
+//        m_listener = _listener;
+//    }
+//
+//    public void run() {
+//        Logger remoteLogger;
+//        Exception listenerException = null;
+//        InputStream is;
+//
+//        if ((this.m_receiver == null) ) {
+//            listenerException =
+//                new Exception(
+//                    "No receiver provided.  Cannot process JSON socket events");
+//            getLogger().error(
+//                "Exception constructing JSON Socket Receiver", listenerException);
+//        }
+//
+//        m_jsonBuffer = new ArrayList<>( 8192 );
+//
+//        try {
+//            is = m_socket.getInputStream();
+//        } catch (Exception e) {
+//            is = null;
+//            listenerException = e;
+//            getLogger().error("Exception opening InputStream to " + m_socket, e);
+//        }
+//
+//        if (is != null) {
+//            String hostName = m_socket.getInetAddress().getHostName();
+//            String remoteInfo = hostName + ":" + m_socket.getPort();
+//            Genson genson = new GensonBuilder()
+//                    .useDateAsTimestamp(true)
+//                    .create();
+//
+//            try {
+//                //read data from the socket.
+//                // Once we have a full JSON message, parse it
+//                ChainsawLoggingEventBuilder build = new ChainsawLoggingEventBuilder();
+//                while (true) {
+//                    getLogger().debug( "About to deserialize values" );
+//                    Iterator<ECSLogEvent> iter = genson.deserializeValues(is, ECSLogEvent.class);
+//                    // Because the socket can be closed, if we don't have anything parsed
+//                    // assume that the socket is closed.
+//                    if( !iter.hasNext() ) break;
+//                    while( iter.hasNext() ){
+//                        ECSLogEvent evt = iter.next();
+//                        m_receiver.append(evt.toChainsawLoggingEvent(build));
+////                        LoggingEvent e = evt.toLoggingEvent();
+////                        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 (m_receiver != null) {
+////                            m_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 (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 (m_listener != null) {
+//            m_listener.socketClosedEvent(listenerException);
+//        }
+//    }
+//}
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
new file mode 100644
index 0000000..3ce8aa8
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.apache.log4j.chainsaw.ChainsawReceiverFactory
@@ -0,0 +1 @@
+org.apache.log4j.net.JsonReceiverFactory