blob: b3c1fd37a91e07f017d85ee3823d385ce6f735dc [file] [log] [blame]
/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed 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.receivers;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.chainsaw.Generator;
import org.apache.log4j.chainsaw.helper.TableCellEditorFactory;
import org.apache.log4j.net.SocketHubReceiver;
import org.apache.log4j.plugins.Plugin;
/**
* A panel that allows the user to edit a particular Plugin, by using introspection
* this class discovers the modifiable properties of the Plugin
* @author Paul Smith <psmith@apache.org>
* @since 1.3
*/
public class PluginPropertyEditorPanel extends JPanel {
private final JScrollPane scrollPane = new JScrollPane();
private final JTable propertyTable = new JTable();
private Plugin plugin;
private TableModel defaultModel = new DefaultTableModel(
new String[] { "Property", "Value" }, 1);
private static final Logger logger = LogManager.getLogger(PluginPropertyEditorPanel.class);
/**
*
*/
public PluginPropertyEditorPanel() {
super();
initComponents();
setupListeners();
}
/**
*
*/
private void initComponents() {
setPreferredSize(new Dimension(160, 120));
setLayout(new BorderLayout());
scrollPane.setViewportView(propertyTable);
add(scrollPane, BorderLayout.CENTER);
propertyTable.setModel(
defaultModel = new DefaultTableModel(
new String[] { "Property", "Value" }, 1));
}
/**
*
*/
private void setupListeners() {
addPropertyChangeListener("plugin", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent 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);
}
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("Property Editor Test bed");
frame.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(1);
}
});
PluginPropertyEditorPanel panel = new PluginPropertyEditorPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
SocketHubReceiver r = new SocketHubReceiver();
panel.setPlugin(r);
try {
Thread.sleep(3000);
panel.setPlugin(new Generator("MyPlugin"));
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* @return Returns the plugin.
*/
public final Plugin getPlugin() {
return plugin;
}
/**
* @param plugin The plugin to set.
*/
public final void setPlugin(Plugin plugin) {
Plugin oldValue = this.plugin;
this.plugin = plugin;
firePropertyChange("plugin", oldValue, this.plugin);
}
/**
* @author psmith
*
*/
private class PluginTableCellEditor extends AbstractCellEditor
implements TableCellEditor {
private Map editorMap = new HashMap();
private DefaultCellEditor defaultEditor = new DefaultCellEditor(
new JTextField());
private DefaultCellEditor currentEditor = defaultEditor;
private PluginTableCellEditor() {
editorMap.put(Boolean.class,
TableCellEditorFactory.createBooleanTableCellEditor());
editorMap.put(Level.class,
TableCellEditorFactory.createLevelTableCellEditor());
//support primitive boolean parameters with the appropriate editor
editorMap.put(boolean.class, TableCellEditorFactory.createBooleanTableCellEditor());
}
/* (non-Javadoc)
* @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable, java.lang.Object, boolean, int, int)
*/
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
PluginPropertyTableModel model = (PluginPropertyTableModel) table.getModel();
PropertyDescriptor descriptor = model.getDescriptors()[row];
Class valueClass = descriptor.getPropertyType();
if (editorMap.containsKey(valueClass)) {
DefaultCellEditor editor =
(DefaultCellEditor) editorMap.get(valueClass);
logger.debug("Located CellEditor for " + valueClass);
currentEditor = editor;
return currentEditor.getTableCellEditorComponent(table, value,
isSelected, row, column);
}
currentEditor = defaultEditor;
logger.debug("Cell value class " + valueClass +
" not know, using default editor");
return defaultEditor.getTableCellEditorComponent(table, value,
isSelected, row, column);
}
/* (non-Javadoc)
* @see javax.swing.CellEditor#getCellEditorValue()
*/
public Object getCellEditorValue() {
return currentEditor.getCellEditorValue();
}
}
private static class PluginPropertyTableModel extends AbstractTableModel {
private final PropertyDescriptor[] descriptors;
private final Plugin plugin;
private PluginPropertyTableModel(Plugin p)
throws IntrospectionException {
super();
BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass());
List list = new ArrayList(Arrays.asList(
beanInfo.getPropertyDescriptors()));
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
PropertyDescriptor d1 = (PropertyDescriptor) o1;
PropertyDescriptor d2 = (PropertyDescriptor) o2;
return d1.getDisplayName().compareToIgnoreCase(
d2.getDisplayName());
}
});
this.plugin = p;
this.descriptors = (PropertyDescriptor[]) list.toArray(
new PropertyDescriptor[0]);
}
/* (non-Javadoc)
* @see javax.swing.table.AbstractTableModel#getValueAt(int, int)
*/
public Object getValueAt(int row, int col) {
PropertyDescriptor d = descriptors[row];
switch (col) {
case 1:
try {
Object object = d.getReadMethod().invoke(plugin,
new Object[0]);
if (object != null) {
return object;
}
} catch (Exception e) {
logger.error(
"Error reading value for PropertyDescriptor " + d);
}
return "";
case 0:
return d.getName();
}
return null;
}
/* (non-Javadoc)
* @see javax.swing.table.AbstractTableModel#getColumnCount()
*/
public int getColumnCount() {
return 2;
}
/* (non-Javadoc)
* @see javax.swing.table.AbstractTableModel#getRowCount()
*/
public int getRowCount() {
return descriptors.length;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#isCellEditable(int, int)
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
// TODO Determine if the property is one of the ones a User could edit
if (columnIndex == 1) {
return descriptors[rowIndex].getWriteMethod() != null;
}
return false;
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#getColumnName(int)
*/
public String getColumnName(int column) {
return (column == 0) ? "Property" : "Value";
}
/* (non-Javadoc)
* @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 1) {
aValue = translateValueIfNeeded(rowIndex, aValue);
logger.debug(
"setValueAt, " + rowIndex + ", " + columnIndex +
", value=" + aValue + ", valueClass" + aValue.getClass());
try {
descriptors[rowIndex].getWriteMethod().invoke(plugin,
new Object[] { aValue });
fireTableCellUpdated(rowIndex, columnIndex);
} catch (IllegalArgumentException e) {
// ignore
} catch (Exception e) {
logger.error(
"Failed to modify the Plugin because of Exception", e);
}
} else {
super.setValueAt(aValue, rowIndex, columnIndex);
}
}
/**
* @param columnIndex
* @param value
* @return
*/
private Object translateValueIfNeeded(int row, Object value) {
if ((descriptors[row].getPropertyType() == int.class) ||
(descriptors[row].getPropertyType() == Integer.class)) {
try {
return Integer.valueOf(value.toString());
} catch (Exception e) {
logger.error("Failed to convert to Integer type");
}
}
return value;
}
/**
* @return Returns the descriptors.
*/
public final PropertyDescriptor[] getDescriptors() {
return descriptors;
}
}
}