/* * 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.felix.mosgi.console.gui; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.Toolkit; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; import javax.swing.tree.TreePath; import javax.swing.JButton; import javax.swing.JTextField; import javax.swing.ImageIcon; import javax.swing.Box; import javax.swing.BoxLayout; import java.util.Enumeration; import java.util.Hashtable; import org.osgi.framework.BundleContext; import org.apache.felix.mosgi.console.ifc.Plugin; import javax.management.NotificationListener; import javax.management.Notification; import javax.management.remote.JMXConnectionNotification; public class NodesTree extends JPanel implements TreeSelectionListener, NotificationListener, ActionListener { private static Hashtable PROTOCOL_PACKAGE_PROVIDER = new Hashtable(); protected static final String TOP_NAME = "Servers"; private static int POOLING_TIME = 3; private static boolean needToRefreshPoolingTime = false; private Activator activator; private static BundleContext bc; protected JTree tree; private DefaultTreeModel dtm; private DefaultMutableTreeNode top = null; private JButton jb_addNode; private JButton jb_removeNode; private JTextField jtf_pool; private JButton jb_refresh; private boolean cont = true; private PoolingThread pt; private boolean isAllNodesConnected = false; public NodesTree(Activator activator, BundleContext bc) { super(new BorderLayout()); this.activator = activator; this.bc = bc; this.pt = new PoolingThread(); System.setProperty("java.security.policy", "client.policy"); top = new DefaultMutableTreeNode(NodesTree.TOP_NAME); dtm = new DefaultTreeModel(top); tree = new JTree(dtm); tree.setCellRenderer(new NodeCellRenderer(bc, this)); tree.addTreeSelectionListener(this); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); javax.swing.ToolTipManager.sharedInstance().registerComponent(tree); JScrollPane treeView = new JScrollPane(tree); add(createButtonPanel(), BorderLayout.NORTH); add(treeView, BorderLayout.CENTER); } public void runDiscovery(){ Gateway[] g = Gateway.newGateways(bc); for (int i = 0 ; i < g.length ; i++) { this.createTreeNode(g[i]); } (new Thread(this.pt)).start(); tree.expandPath(new TreePath(((DefaultMutableTreeNode)(dtm.getRoot())).getPath())); // expand root node } ////////////////////////////////////////////////////// // TreeSelectionListener // ////////////////////////////////////////////////////// public void valueChanged(TreeSelectionEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(); if (node!=null) { Object selected = node.getUserObject(); if ( !selected.equals(NodesTree.TOP_NAME) ) { Gateway g = (Gateway) selected; Object mbsc = g.getMbsc(); if ( mbsc != null ){ activator.firePropertyChangedEvent(Plugin.NEW_NODE_SELECTED, g.toString(), mbsc); } else { activator.firePropertyChangedEvent(Plugin.EMPTY_NODE, null, "null"); } } } } //////////////////////////////////////////////////// // NotificationListener // //////////////////////////////////////////////////// public void handleNotification(Notification notification, Object handback) { //System.out.println("Connection ==> "+notification.getMessage()+":"+((JMXConnectionNotification)notification).getConnectionId()+":"+handback); if ( !JMXConnectionNotification.OPENED.equals(notification.getType()) ){ Enumeration enu = top.breadthFirstEnumeration(); enu.nextElement(); // Skip top node while ( enu.hasMoreElements() ) { Object o = ((DefaultMutableTreeNode) enu.nextElement()).getUserObject(); Gateway g = (Gateway) o; if ( g.toString().equals(handback.toString()) ) { if ( g.isConnected() ) { g.disconnect(this); DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if ( selectedNode != null ) { Gateway g_selected = (Gateway) selectedNode.getUserObject(); if ( g_selected.toString().equals(g.toString()) ) { activator.firePropertyChangedEvent(Plugin.EMPTY_NODE, null, "null"); } } tree.treeDidChange(); isAllNodesConnected = false; } } } } } //////////////////////////////////////////////////// // Friend methods // //////////////////////////////////////////////////// void stop() { this.cont = false; } public void actionPerformed(ActionEvent ae) { Object object = ae.getSource(); if ( object == jb_addNode ) { // Add a new node into tree DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(); Gateway selectedGateway = null; if ( node != null && node != top) { selectedGateway = (Gateway) node.getUserObject(); } Gateway newGateway = null; try { newGateway = Gateway.newGateway(selectedGateway); } catch (Exception exep) { JOptionPane.showMessageDialog(null, "Gateway creation error:\n "+exep.toString(), "Error", JOptionPane.ERROR_MESSAGE); } if ( newGateway != null ) { TreePath tp = tree.getSelectionPath(); this.createTreeNode(newGateway); dtm.reload(top); isAllNodesConnected = false; tree.setSelectionPath(tp); } } else if ( object == jb_removeNode ) { // Remove a node from tree DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent(); if ( node == null || !node.isLeaf() ) { JOptionPane.showMessageDialog(null, "Please select a gateway (without child gateway) to remove.", "Warning", JOptionPane.WARNING_MESSAGE); } else if ( node != top) { Gateway g = (Gateway) node.getUserObject(); if ( !node.equals(top) ){ if( JOptionPane.showConfirmDialog(null, "Sure we remove gateway \""+g.getNickname()+"\" ?\n "+g.toString(), "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION ) { g.disconnect(this); dtm.removeNodeFromParent(node); Gateway.HT_GATEWAY.remove(g.getNickname()); System.out.println("Remove node : "+g); } } } } else if ( object == jtf_pool) { try { POOLING_TIME = Integer.parseInt(jtf_pool.getText()); if ( POOLING_TIME < 0 ) { POOLING_TIME = 0; } else if ( POOLING_TIME > 999 ) { POOLING_TIME = 999; } } catch (Exception exep) { // } if ( POOLING_TIME > 0 ) { jb_refresh.setEnabled(false); } else { jb_refresh.setEnabled(true); } jtf_pool.setText(""+POOLING_TIME); needToRefreshPoolingTime = true; } else if ( object == jb_refresh) { tryToConnectAllNodes(); } } /////////////////////////////////////////////////// // Private part // /////////////////////////////////////////////////// private void tryToConnectAllNodes() { isAllNodesConnected = true; Enumeration enu = top.breadthFirstEnumeration(); enu.nextElement(); // Skip top node while ( enu.hasMoreElements() ) { Gateway g = (Gateway) (((DefaultMutableTreeNode) enu.nextElement()).getUserObject()); if ( !g.isConnected() ) { if ( !g.connect(this) ) { isAllNodesConnected = false; } else { tree.treeDidChange(); activator.firePropertyChangedEvent(Plugin.NEW_NODE_CONNECTION, g.toString(), g.getMbsc()); // If new connected is the selected one then create a false valueChanged in order to load the NodePanel : DefaultMutableTreeNode selected_node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if ( selected_node != null && !selected_node.equals(top) ) { Gateway g_selected = (Gateway) (selected_node.getUserObject()); if ( g_selected == g ) { this.valueChanged(null); } else { } } } } } } private class PoolingThread implements Runnable { public void run() { while ( cont ) { if ( !isAllNodesConnected && POOLING_TIME > 0 ) { tryToConnectAllNodes(); } int loop = POOLING_TIME; while ( loop-- > 0 & !needToRefreshPoolingTime ) { try { Thread.sleep(1000); } catch(InterruptedException ie) { //ie.printStackTrace(); } } needToRefreshPoolingTime = false; } } } protected static String getProtocolPackageProvider(String protoName) { Object o = PROTOCOL_PACKAGE_PROVIDER.get(protoName); if ( o != null) { return (String) o; } else { String packages = bc.getProperty("mosgi.jmxconsole.protocol."+protoName+".package"); if ( packages == null ) { packages = ""; } else { System.out.println("Protocol provider package for \""+protoName+"\" is prefixed with \""+packages+"\""); } PROTOCOL_PACKAGE_PROVIDER.put(protoName, packages); return packages; } } private void createTreeNode(Gateway g) { DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(g); DefaultMutableTreeNode parentNode = null; Gateway parent = g.getParent(); if ( parent != null ) { Enumeration enu = top.breadthFirstEnumeration(); while ( enu.hasMoreElements() ) { DefaultMutableTreeNode dmtn_tmp = (DefaultMutableTreeNode) enu.nextElement(); if ( dmtn_tmp.getUserObject().equals(parent) ) { parentNode = dmtn_tmp; break; } } } if ( parentNode == null ) { parentNode = top; } parentNode.add(dmtn); } private JPanel createButtonPanel(){ JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); //border... buttonPanel.add(Box.createHorizontalGlue()); jb_addNode = new MyButton('a', "ADD.gif", "Add a gateway", this, buttonPanel); buttonPanel.add(Box.createRigidArea(new Dimension(2,0))); jb_removeNode = new MyButton('d', "REMOVE.gif", "Remove selected gateway", this, buttonPanel); buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(Box.createRigidArea(new Dimension(2,0))); buttonPanel.add(Box.createHorizontalGlue()); jtf_pool = new JTextField(""+POOLING_TIME); jtf_pool.addActionListener(this); jtf_pool.setToolTipText("<html>Pooling interval in seconds<br>Value range is 1 to 999<br>A value of 0 means no refresh.</html>"); jtf_pool.setPreferredSize(new Dimension(40,21)); jtf_pool.setMaximumSize(new Dimension(40,21)); buttonPanel.add(jtf_pool); buttonPanel.add(Box.createRigidArea(new Dimension(2,0))); jb_refresh = new JButton(new ImageIcon(Toolkit.getDefaultToolkit().getImage(bc.getBundle().getResource("images/"+"REFRESH.gif")))); jb_refresh.setOpaque(true); jb_refresh.setToolTipText("<html>Try to connect to gateways now.<br>Enabled only if there is no pooling time.</html>"); jb_refresh.addActionListener(this); jb_refresh.setPreferredSize(new Dimension(18, 18)); jb_refresh.setEnabled(false); buttonPanel.add(jb_refresh); buttonPanel.add(Box.createHorizontalGlue()); return buttonPanel; } static class MyButton extends JButton { private final int W = 18, H = 18; public MyButton(char c, String iconName, String ttt, NodesTree listener, JPanel panel) { super(new ImageIcon(Toolkit.getDefaultToolkit().getImage(bc.getBundle().getResource("images/"+iconName)))); super.setMnemonic(c); super.setToolTipText(ttt); super.setBorder(null); super.setPreferredSize(new Dimension(W, H)); super.addActionListener(listener); panel.add(this); } } }