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