/*
D-Bus Java Viewer
Copyright (c) 2006 Peter Cox
This program is free software; you can redistribute it and/or modify it
under the terms of either the GNU Lesser General Public License Version 2 or the
Academic Free Licence Version 2.1.
Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus.viewer;
import static org.freedesktop.dbus.Gettext._;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.TableModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.freedesktop.DBus;
import org.freedesktop.DBus.Introspectable;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.UInt32;
import org.freedesktop.dbus.exceptions.DBusException;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* A viewer for DBus
*
* goal is to replicate the functionality of kdbus with Java smarts
*
* @author pete
* @since 29/01/2006
*/
public class DBusViewer
{
private static final Map<String, Integer> CONNECTION_TYPES = new HashMap<String, Integer>();
static
{
CONNECTION_TYPES.put("System", DBusConnection.SYSTEM);
CONNECTION_TYPES.put("Session", DBusConnection.SESSION);
}
/** Create the DBusViewer
*
* @param connectionTypes The map of connection types
*/
public DBusViewer(final Map<String, Integer> connectionTypes)
{
connections = new ArrayList<DBusConnection>(connectionTypes.size());
SwingUtilities.invokeLater(new Runnable()
{
@SuppressWarnings("synthetic-access")
public void run()
{
final JTabbedPane tabbedPane = new JTabbedPane();
addTabs(tabbedPane, connectionTypes);
final JFrame frame = new JFrame("Dbus Viewer");
frame.setContentPane(tabbedPane);
frame.setSize(600, 400);
frame.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
frame.dispose();
for (DBusConnection connection : connections)
{
connection.disconnect();
}
System.exit(0);
}
});
frame.setVisible(true);
}
});
}
private List<DBusConnection> connections;
/**
* @param args
*/
public static void main(String[] args)
{
new DBusViewer(CONNECTION_TYPES);
}
/** Add tabs for each supplied connection type
* @param tabbedPane The tabbed pane
* @param connectionTypes The connection
*/
private void addTabs(final JTabbedPane tabbedPane,
final Map<String, Integer> connectionTypes)
{
for (final String key : connectionTypes.keySet())
{
final JLabel label = new JLabel(_("Processing DBus for ") + key);
tabbedPane.addTab(key, label);
}
Runnable loader = new Runnable()
{
@SuppressWarnings("synthetic-access")
public void run()
{
boolean users = true, owners = true;
for (final String key : connectionTypes.keySet())
{
try
{
DBusConnection conn = DBusConnection
.getConnection(connectionTypes.get(key));
connections.add(conn);
final TableModel tableModel = listDBusConnection(users,
owners, conn);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
int index = tabbedPane.indexOfTab(key);
final JTable table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
JPanel tab = new JPanel(new BorderLayout());
tab.add(scrollPane, BorderLayout.CENTER);
JPanel southPanel = new JPanel();
final JButton button = new JButton(new IntrospectAction(table));
southPanel.add(button);
tab.add(southPanel, BorderLayout.SOUTH);
tabbedPane.setComponentAt(index,
tab);
}
});
}
catch (final DBusException e)
{
e.printStackTrace();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
int index = tabbedPane.indexOfTab(key);
JLabel label = (JLabel) tabbedPane
.getComponentAt(index);
label
.setText(_("Could not load Dbus information for ")
+ key + ":" + e.getMessage());
}
});
}
catch (final DBusExecutionException e)
{
e.printStackTrace();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
int index = tabbedPane.indexOfTab(key);
JLabel label = (JLabel) tabbedPane
.getComponentAt(index);
label
.setText(_("Could not load Dbus information for ")
+ key + ":" + e.getMessage());
}
});
}
}
}
};
final Thread thread = new Thread(loader);
thread.setName("DBus Loader");
thread.start();
}
/* based on code from org.freedesktop.dbus.ListDBus */
private DBusTableModel listDBusConnection(boolean users, boolean owners,
DBusConnection conn) throws DBusException
{
DBusTableModel model = new DBusTableModel();
DBus dbus = conn.getRemoteObject("org.freedesktop.DBus",
"/org/freedesktop/DBus", DBus.class);
String[] names = dbus.ListNames();
ParsingContext p = new ParsingContext(conn);
for (String name : names)
{
List<DBusEntry> results = new ArrayList<DBusEntry>();
try
{
//String objectpath = '/' + name.replace('.', '/');
p.visitNode(name,"/");
}
catch (DBusException e)
{
e.printStackTrace();
}
catch (DBusExecutionException e)
{
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
results = p.getResult();
p.reset();
if (results.size()>0) {
if (users) try
{
final UInt32 user = dbus.GetConnectionUnixUser(name);
for (DBusEntry entry : results) {
entry.setUser(user);
}
}
catch (DBusExecutionException DBEe)
{
}
if (!name.startsWith(":") && owners)
{
try
{
final String owner = dbus.GetNameOwner(name);
for (DBusEntry entry : results) {
entry.setOwner(owner);
}
}
catch (DBusExecutionException DBEe)
{
}
}
for (DBusEntry entry : results) {
model.add(entry);
}
}
}
return model;
}
private final static String DOC_TYPE = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">";
class ParsingContext {
private DBusConnection conn;
private DocumentBuilder builder;
private List<DBusEntry> result;
ParsingContext(DBusConnection conn) {
this.conn = conn;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
// TODO Auto-generated catch block
throw new RuntimeException(_("Error during parser init: ")+e1.getMessage(),e1);
}
reset();
}
DBusEntry addEntry(String name, String path) throws DBusException {
DBusEntry entry = new DBusEntry();
entry.setName(name);
entry.setPath(path);
Introspectable introspectable = conn.getRemoteObject(name, path, Introspectable.class);
entry.setIntrospectable(introspectable);
result.add(entry);
return entry;
}
public void visitNode(String name, String path) throws DBusException, SAXException, IOException {
System.out.println("visit "+name+":"+path);
if ("/org/freedesktop/DBus/Local".equals(path)) {
// this will disconnects us.
return;
}
DBusEntry e = addEntry(name, path);
String introspectData = e.getIntrospectable().Introspect();
Document document = builder.parse(new InputSource(new StringReader(introspectData.replace(DOC_TYPE, ""))));
Element root = document.getDocumentElement();
NodeList children = root.getChildNodes();
for (int i=0;i<children.getLength();i++) {
Node node = children.item(i);
if (Node.ELEMENT_NODE != node.getNodeType()) {
continue;
}
if ("node".equals(node.getNodeName())) {
Node nameNode = node.getAttributes().getNamedItem("name");
if (nameNode!=null) {
try {
if (path.endsWith("/")) {
visitNode(name, path + nameNode.getNodeValue());
} else {
visitNode(name, path + '/' + nameNode.getNodeValue());
}
} catch (DBusException ex) {
ex.printStackTrace();
}
}
}
}
}
public List<DBusEntry> getResult() {
return result;
}
void reset() {
result = new ArrayList<DBusEntry>();
}
}
}