/* * This class is part of the OSGiJMX plugin for the VisualVM, allowing * to have some basic administration functionality over an OSGi platform * * Copyright (C) 2009 Kiev Gama (kiev.gama at gmail.com) * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * **/ package osgijmx.vvm; import com.sun.tools.visualvm.application.Application; import com.sun.tools.visualvm.core.ui.DataSourceView; import com.sun.tools.visualvm.core.ui.components.DataViewComponent; import com.sun.tools.visualvm.tools.jmx.JmxModelFactory; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Map.Entry; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.Notification; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.management.JMX; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeType; import javax.management.openmbean.TabularData; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableColumnModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import org.netbeans.lib.profiler.ui.UIConstants; import org.netbeans.lib.profiler.ui.UIUtils; import org.netbeans.lib.profiler.ui.components.JExtendedTable; import org.netbeans.lib.profiler.ui.components.table.LabelTableCellRenderer; import org.openide.util.Utilities; import osgijmx.BundleMXBean; import osgijmx.OSGiPlatformMXBean; /** * * @author kiev */ public class BundlesView extends DataSourceView { private DataViewComponent dvc; //Reusing an image from the sources: private static final String IMAGE_PATH = "/resources/icon.png"; // NOI18N private JLabel generalInfo; private JTable bundleTable; private BundlesTableModel tableModel; private MBeanServerConnection mbs; private JTextField bundleURL; private JButton installBtn; public BundlesView(Application application) { super(application, "OSGi", new ImageIcon(Utilities.loadImage(IMAGE_PATH, true)).getImage(), 60, false); mbs = JmxModelFactory.getJmxModelFor(application).getMBeanServerConnection(); try { mbs.addNotificationListener(new ObjectName("osgijmx:type=framework"), new NotificationListener() { public void handleNotification(Notification notification, Object handback) { updateFrameworkInfo(); tableModel.fireTableDataChanged(); } }, null, null); } catch (Exception ex) { ex.printStackTrace(); } } @Override protected DataViewComponent createComponent() { initView(); updateFrameworkInfo(); return dvc; } private OSGiPlatformMXBean getFrameworkMXBean() throws NullPointerException, MalformedObjectNameException { ObjectName objName = new ObjectName("osgijmx:type=framework"); OSGiPlatformMXBean osgiProxy = JMX.newMXBeanProxy(mbs, objName, OSGiPlatformMXBean.class); return osgiProxy; } private void updateFrameworkInfo() { try { OSGiPlatformMXBean osgiProxy = getFrameworkMXBean(); StringBuilder sb = new StringBuilder(); sb.append("Total Bundles: "); sb.append(osgiProxy.getBundles().size()); sb.append("
Framework version: "); sb.append(osgiProxy.getFrameworkVersion()); sb.append("
Framework vendor: "); sb.append(osgiProxy.getFrameworkVendor()); this.generalInfo.setText(sb.toString()); this.tableModel.setBundles(osgiProxy.getBundles()); osgiProxy.getBundle(1).getBundleHeaders().size(); } catch (MalformedObjectNameException ex) { this.generalInfo.setText("OSGi MBean not found"); } } private void initView() { generalInfo = new JLabel(); generalInfo.setBorder(BorderFactory.createEmptyBorder(14, 8, 14, 8)); tableModel = new BundlesTableModel(new ArrayList()); bundleTable = new JExtendedTable(tableModel); bundleTable.setBorder(BorderFactory.createEmptyBorder()); bundleTable.setRowSelectionAllowed(true); bundleTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); bundleTable.setGridColor(UIConstants.TABLE_VERTICAL_GRID_COLOR); bundleTable.setSelectionBackground(UIConstants.TABLE_SELECTION_BACKGROUND_COLOR); bundleTable.setSelectionForeground(UIConstants.TABLE_SELECTION_FOREGROUND_COLOR); bundleTable.setShowHorizontalLines(UIConstants.SHOW_TABLE_HORIZONTAL_GRID); bundleTable.setShowVerticalLines(UIConstants.SHOW_TABLE_VERTICAL_GRID); bundleTable.setRowMargin(UIConstants.TABLE_ROW_MARGIN); bundleTable.setRowHeight(UIUtils.getDefaultRowHeight() + 2); final JLabel manifestLabel = new JLabel(); final JLabel entriesLabel = new JLabel(); final JTree tree = new JTree(new DefaultMutableTreeNode("Services")); final JPopupMenu menu = new JPopupMenu(); menu.add(new BundleAction(BundleActionType.Start)); menu.add(new BundleAction(BundleActionType.Stop)); menu.add(new BundleAction(BundleActionType.Update)); menu.add(new BundleAction(BundleActionType.Uninstall)); LabelTableCellRenderer trailRenderer = new LabelTableCellRenderer(JLabel.TRAILING); LabelTableCellRenderer leadingRenderer = new LabelTableCellRenderer(JLabel.LEADING); TableColumnModel colModel = bundleTable.getColumnModel(); for (int i = 0; i < colModel.getColumnCount(); i++) { if (i == BundlesTableModel.COLUMN_ID) { colModel.getColumn(i).setCellRenderer(trailRenderer); colModel.getColumn(i).setPreferredWidth(30); } else { colModel.getColumn(i).setCellRenderer(leadingRenderer); } } DataViewComponent.MasterView masterView = new DataViewComponent.MasterView("Bundles Overview", null, generalInfo); DataViewComponent.MasterViewConfiguration masterConfiguration = new DataViewComponent.MasterViewConfiguration(false); //master view and configuration view dvc = new DataViewComponent(masterView, masterConfiguration); //Add configuration details to the component, which are the show/hide checkboxes at the top: dvc.configureDetailsArea(new DataViewComponent.DetailsAreaConfiguration( "Bundle List", true), DataViewComponent.TOP_LEFT); dvc.configureDetailsArea(new DataViewComponent.DetailsAreaConfiguration( "Bundle Details", true), DataViewComponent.BOTTOM_LEFT); JPanel bundlesPanel = new JPanel(new BorderLayout()); JPanel installBundlePanel = new JPanel(); bundleURL = new JTextField(40); installBtn = new JButton(new BundleAction(BundleActionType.Install)); installBundlePanel.add(new JLabel("Bundle path: ")); installBundlePanel.add(bundleURL); installBundlePanel.add(installBtn); installBundlePanel.setBackground(Color.WHITE); JScrollPane scroll = new JScrollPane(bundleTable); scroll.setBorder(BorderFactory.createEmptyBorder()); bundlesPanel.add(scroll, BorderLayout.CENTER); bundlesPanel.add(installBundlePanel, BorderLayout.SOUTH); //component detail views dvc.addDetailsView(new DataViewComponent.DetailsView( "Bundle List", null, 10, bundlesPanel, null), DataViewComponent.TOP_LEFT); dvc.addDetailsView(new DataViewComponent.DetailsView( "Manifest Headers", null, 10, wrapComponent(manifestLabel, BorderLayout.NORTH), null), DataViewComponent.BOTTOM_LEFT); dvc.addDetailsView(new DataViewComponent.DetailsView( "Provided Services", null, 10, wrapComponent(tree, BorderLayout.CENTER), null), DataViewComponent.BOTTOM_LEFT); dvc.addDetailsView(new DataViewComponent.DetailsView( "Contents", null, 10, wrapComponent(entriesLabel, BorderLayout.NORTH), null), DataViewComponent.BOTTOM_LEFT); dvc.setOpaque(false); bundleTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { //updates the detailed data if the bundle selection changes public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting() && !bundleTable.getSelectionModel().isSelectionEmpty()) { StringBuilder sb = new StringBuilder(""); BundleMXBean bean = getSelectedBundle(); //manifest entries for (Entry entry : bean.getBundleHeaders().entrySet()) { sb.append("").append(entry.getKey()).append(": "); sb.append(entry.getValue()).append("
"); } manifestLabel.setText(sb.toString()); //files and folder entries sb = new StringBuilder(""); for (String s : bean.getAllEntries()) { sb.append(s).append("
"); } entriesLabel.setText(sb.toString()); //Provided services try { //work around... Object o = mbs.getAttribute(new ObjectName("osgijmx:type=bundle,id=" + bean.getBundleId()), "RegisteredServices"); sb.append(((TabularData) o).values().toArray()); DefaultMutableTreeNode root = new DefaultMutableTreeNode("Services"); parseTreeModel((TabularData) o, root); tree.setModel(new DefaultTreeModel(root)); } catch (Exception ex) { //TODO handle errors with user message ex.printStackTrace(); } } } }); // Set the component to show the popup menu bundleTable.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { showPopup(evt); } public void mouseReleased(MouseEvent evt) { showPopup(evt); } private void showPopup(MouseEvent evt) { if (evt.isPopupTrigger()) { int rowNumber = bundleTable.rowAtPoint(evt.getPoint()); // Get the ListSelectionModel of the JTable ListSelectionModel model = bundleTable.getSelectionModel(); if (rowNumber > - 1) { model.setSelectionInterval(rowNumber, rowNumber); menu.show(evt.getComponent(), evt.getX(), evt.getY()); } } } }); } //builds the tree model private void parseTreeModel(TabularData o, DefaultMutableTreeNode node) { if (o != null) { Object[] data = o.values().toArray(); for (Object element : data) { CompositeData item = (CompositeData) element; CompositeType type = item.getCompositeType(); Set keys = type.keySet(); ArrayList a = new ArrayList(keys); for (int i = 0; i < a.size();) { String key = (String) item.get((String) a.get(i++)); Object val = item.get((String) a.get(i++)); DefaultMutableTreeNode newNode; if (val instanceof TabularData) { newNode = new DefaultMutableTreeNode(key); parseTreeModel((TabularData) val, newNode); } else { newNode = new DefaultMutableTreeNode(key + " " + val); } node.add(newNode); } } } } private JScrollPane wrapComponent(JComponent component, String borderLayoutPos) { JPanel panel = new JPanel(new BorderLayout()); JScrollPane scroll = new JScrollPane(panel); panel.setBackground(Color.WHITE); panel.add(component, borderLayoutPos); component.setBorder(BorderFactory.createEmptyBorder()); scroll.setBorder(BorderFactory.createEmptyBorder()); scroll.setBackground(Color.WHITE); return scroll; } private BundleMXBean getSelectedBundle() { BundleMXBean bean = tableModel.getRowBean(bundleTable.getSelectionModel().getMinSelectionIndex()); return bean; } class BundleAction extends AbstractAction { private BundleActionType type; BundleAction(BundleActionType type) { this.putValue(NAME, type.toString()); this.type = type; } public void actionPerformed(ActionEvent e) { try { switch (type) { case Install: getFrameworkMXBean().installBundle(bundleURL.getText()); break; case Start: getSelectedBundle().start(); break; case Stop: getSelectedBundle().stop(); break; case Update: getSelectedBundle().update(); break; case Uninstall: getSelectedBundle().uninstall(); break; } } catch (Exception ex) { //TODO show friendly UI message... throw new RuntimeException(ex); } } } enum BundleActionType { Install, Start, Stop, Update, Uninstall; } }