Package org.jboss.cache.demo

Source Code of org.jboss.cache.demo.JBossCacheDemo$ClusterTableModel

package org.jboss.cache.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.CacheStatus;
import static org.jboss.cache.CacheStatus.*;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.notifications.annotation.BuddyGroupChanged;
import org.jboss.cache.notifications.annotation.NodeCreated;
import org.jboss.cache.notifications.annotation.NodeModified;
import org.jboss.cache.notifications.annotation.NodeMoved;
import org.jboss.cache.notifications.annotation.NodeRemoved;
import org.jboss.cache.notifications.annotation.ViewChanged;
import org.jboss.cache.notifications.event.BuddyGroupChangedEvent;
import org.jboss.cache.notifications.event.NodeCreatedEvent;
import org.jboss.cache.notifications.event.NodeModifiedEvent;
import org.jboss.cache.notifications.event.NodeMovedEvent;
import org.jboss.cache.notifications.event.NodeRemovedEvent;
import org.jboss.cache.notifications.event.ViewChangedEvent;
import org.jboss.cache.util.CachePrinter;
import org.jgroups.Address;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.tree.TreePath;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
* @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
*/
public class JBossCacheDemo
{
   private static Log log = LogFactory.getLog(JBossCacheDemo.class);
   private static JFrame frame;
   private JTabbedPane mainPane;
   private JPanel panel1;
   private JLabel cacheStatus;
   private JPanel dataGeneratorTab;
   private JPanel statisticsTab;
   private JPanel clusterViewTab;
   private JPanel dataViewTab;
   private JPanel controlPanelTab;
   private JTree dataTree;
   private JTable clusterTable;
   private JButton actionButton;
   private JLabel configFileName;
   private JProgressBar cacheStatusProgressBar;
   private JTextField fqnTextField;
   private JTextField keyTextField;
   private JTextField valueTextField;
   private JRadioButton createNodeRadioButton;
   private JRadioButton removeNodeRadioButton;
   private JRadioButton addKeyRadioButton;
   private JRadioButton removeKeyRadioButton;
   private JButton goButton;
   private JTable nodeDataTable;
   private JScrollPane nodeDataScrollPane;
   private JButton randomGeneratorButton;
   private JTextField maxNodesTextField;
   private JTextField maxDepthTextField;
   private JTextField numberOfKeysPerTextField;
   private JButton cacheClearButton;
   private JButton updateStatsButton;
   private JLabel statsNumberOfNodes;
   private JLabel statsNumberOfKeys;
   private JLabel statsSizeOfCachedData;
   private JLabel statsLastUpdated;
   private JTextArea configFileContents;
   private JRadioButton getNodeRadioButton;
   private JScrollPane treeScrollPane;
   private JPanel debugTab;
   private JButton cacheDetailsButton;
   private JButton cacheLockInfoButton;
   private JTextArea debugTextArea;
   private String cacheConfigFile;
   private Cache<String, String> cache;
   private String startCacheButtonLabel = "Start Cache", stopCacheButtonLabel = "Stop Cache";
   private String statusStarting = "Starting Cache ... ", statusStarted = "Cache Running.", statusStopping = "Stopping Cache ...", statusStopped = "Cache Stopped.";
   private ExecutorService asyncExecutor;
   private BlockingQueue<Runnable> asyncTaskQueue;
   private ClusterTableModel clusterDataModel;
   private NodeDataTableModel nodeDataTableModel;
   private DataTreeRefresher treeRefresher;
   private Random r = new Random();
   private boolean isUsingBuddyReplication;

   public static void main(String[] args)
   {
      String cfgFileName = "demo-cache-config.xml";
      if (args.length == 1 && args[0] != null && args[0].toLowerCase().endsWith(".xml"))
      {
         // the first arg is the name of the config file.
         cfgFileName = args[0];
      }

      frame = new JFrame("JBoss Cache GUI Demo (STOPPED)");
      frame.setContentPane(new JBossCacheDemo(cfgFileName).panel1);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setVisible(true);
      frame.setResizable(true);
   }

   public JBossCacheDemo(String cfgFileName)
   {
      asyncExecutor = Executors.newFixedThreadPool(1);
      asyncTaskQueue = ((ThreadPoolExecutor) asyncExecutor).getQueue();

      cacheConfigFile = cfgFileName;
      cacheStatusProgressBar.setVisible(false);
      cacheStatusProgressBar.setEnabled(false);
      configFileName.setText(cacheConfigFile);
      // default state of the action button should be unstarted.
      actionButton.setText(startCacheButtonLabel);
      cacheStatus.setText(statusStopped);

      clusterDataModel = new ClusterTableModel();
      clusterTable.setModel(clusterDataModel);

      nodeDataTableModel = new NodeDataTableModel();
      nodeDataTable.setModel(nodeDataTableModel);

      // when we start up scan the classpath for a file named
      actionButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if (actionButton.getText().equals(startCacheButtonLabel))
            {
               // start cache
               startCache();
            }
            else if (actionButton.getText().equals(stopCacheButtonLabel))
            {
               // stop cache
               stopCache();
            }
         }
      });
      goButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            processAction(goButton, true);

            // do this in a separate thread
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  // based on the value of the radio button:
                  if (createNodeRadioButton.isSelected())
                  {
                     cache.put(fqnTextField.getText(), keyTextField.getText(), valueTextField.getText());
                  }
                  else if (removeNodeRadioButton.isSelected())
                  {
                     cache.removeNode(fqnTextField.getText());
                  }
                  else if (addKeyRadioButton.isSelected())
                  {
                     cache.put(fqnTextField.getText(), keyTextField.getText(), valueTextField.getText());
                  }
                  else if (removeKeyRadioButton.isSelected())
                  {
                     cache.remove(fqnTextField.getText(), keyTextField.getText());
                  }
                  else if (getNodeRadioButton.isSelected())
                  {
                     // do a cache.get on the Fqn first, this may involve a data gravitation
                     // only do this if BR is enabled as it may involve a data gravitation event
                     if (isUsingBuddyReplication)
                        cache.getInvocationContext().getOptionOverrides().setForceDataGravitation(true);
                     cache.getNode(fqnTextField.getText());
                  }
                  treeRefresher.repaint();
                  dataViewTab.repaint();
                  processAction(goButton, false);
                  // now switch to the data pane
                  mainPane.setSelectedIndex(1);
               }
            });
         }
      });
      removeNodeRadioButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            fqnTextField.setEnabled(true);
            keyTextField.setEnabled(false);
            valueTextField.setEnabled(false);
         }
      });
      removeKeyRadioButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            fqnTextField.setEnabled(true);
            keyTextField.setEnabled(true);
            valueTextField.setEnabled(false);
         }
      });
      createNodeRadioButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            fqnTextField.setEnabled(true);
            keyTextField.setEnabled(true);
            valueTextField.setEnabled(true);
         }
      });
      addKeyRadioButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            fqnTextField.setEnabled(true);
            keyTextField.setEnabled(true);
            valueTextField.setEnabled(true);
         }
      });
      getNodeRadioButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            fqnTextField.setEnabled(true);
            keyTextField.setEnabled(false);
            valueTextField.setEnabled(false);
         }
      });

      dataTree.addTreeSelectionListener(new TreeSelectionListener()
      {
         public void valueChanged(TreeSelectionEvent e)
         {
            TreePath path = e.getPath();
            DataTreeRefresher.FqnTreeNode node = (DataTreeRefresher.FqnTreeNode) path.getLastPathComponent();
            Fqn f = node.getFqn();
            if (!f.equals(nodeDataTableModel.getCurrentFqn()))
            {
               nodeDataTableModel.setCurrentFqn(f);
               Node n = cache.getNode(f);
               if (n != null) nodeDataTableModel.setData(n.getData());
            }
         }
      });
      randomGeneratorButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            processAction(randomGeneratorButton, true);

            // process this asynchronously
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  int depth = 1;
                  try
                  {
                     depth = Integer.parseInt(maxDepthTextField.getText());
                  }
                  catch (NumberFormatException nfe)
                  {
                     log.warn("Entered a non-integer for depth.  Using 1.", nfe);
                  }

                  int maxNodes = 1;
                  try
                  {
                     maxNodes = Integer.parseInt(maxNodesTextField.getText());
                  }
                  catch (NumberFormatException nfe)
                  {
                     log.warn("Entered a non-integer for max nodes.  Using 1.", nfe);
                  }

                  int attribsPerNode = 1;
                  try
                  {
                     attribsPerNode = Integer.parseInt(numberOfKeysPerTextField.getText());
                  }
                  catch (NumberFormatException nfe)
                  {
                     log.warn("Entered a non-integer for keys per node.  Using 1.", nfe);
                  }

                  Set<Fqn> fqns = new HashSet<Fqn>();
                  for (int i = 0; i < maxNodes; i++)
                  {
                     Fqn fqn = createRandomFqn(depth);
                     while (fqns.contains(fqn)) fqn = createRandomFqn(depth);
                     fqns.add(fqn);
                  }

                  for (Fqn f : fqns)
                  {
                     Map m = new HashMap();
                     for (int i = 0; i < attribsPerNode; i++) m.put(randomString(), randomString());
                     cache.put(f, m);
                  }

                  processAction(randomGeneratorButton, false);
                  // now switch to the data pane
                  mainPane.setSelectedIndex(1);
               }
            });
         }

         private Fqn createRandomFqn(int depth)
         {
            String s = "/";
            for (int i = 0; i < r.nextInt(depth); i++)
            {
               s += randomString() + "/";
            }
            return Fqn.fromString(s);
         }

         private String randomString()
         {
            return Integer.toHexString(r.nextInt(Integer.MAX_VALUE)).toUpperCase();
         }
      });
      cacheClearButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            processAction(cacheClearButton, true);
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  cache.removeNode(Fqn.ROOT);
                  cache.getRoot().clearData();
                  processAction(cacheClearButton, false);
                  // now switch to the data pane
                  mainPane.setSelectedIndex(1);
               }
            });
         }
      });
      updateStatsButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            processAction(updateStatsButton, true);
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  updateStats();
                  processAction(updateStatsButton, false);
               }
            });
         }
      });
      cacheDetailsButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if (cache != null) debugTextArea.setText(CachePrinter.printCacheDetails(cache));
         }
      });
      cacheLockInfoButton.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if (cache != null) debugTextArea.setText(CachePrinter.printCacheLockingInfo(cache));
         }
      });
   }

   private void updateStats()
   {
      int numNodes = ((CacheSPI) cache).getNumberOfNodes();
      statsNumberOfNodes.setText(numNodes + " nodes");
      Map<String, Long> values = new HashMap<String, Long>();
      values.put("NumKeys", 0l);
      values.put("Size", 0l);
      processRecursively(cache.getRoot(), values);
      statsNumberOfKeys.setText(values.get("NumKeys") + " keys");
      NumberFormat format = NumberFormat.getIntegerInstance();
      statsSizeOfCachedData.setText(format.format(values.get("Size")) + " bytes");
      statsLastUpdated.setText(new Date().toString());
   }

   private void processRecursively(Node<String, String> node, Map<String, Long> values)
   {
      // process children first
      for (Node child : node.getChildren())
      {
         processRecursively(child, values);
      }
      // now process current node
      Map data = node.getData();
      values.put("NumKeys", values.get("NumKeys") + data.size());
      values.put("Size", values.get("Size") + calculateSize(data));
   }

   private int calculateSize(Map<String, String> data)
   {
      // since all we have are strings:
      int size = 0;
      for (String key : data.keySet())
      {
         size += key.length();
         size += data.get(key).length();
      }
      return size;
   }

   private void moveCacheToState(CacheStatus state)
   {
      switch (state)
      {
         case STARTING:
            cacheStatus.setText(statusStarting);
            processAction(actionButton, true);
            break;
         case STARTED:
            setCacheTabsStatus(true);
            actionButton.setText(stopCacheButtonLabel);
            processAction(actionButton, false);
            cacheStatus.setText(statusStarted);
            updateTitleBar();
            break;
         case STOPPING:
            cacheStatus.setText(statusStopping);
            processAction(actionButton, true);
            break;
         case STOPPED:
            setCacheTabsStatus(false);
            actionButton.setText(startCacheButtonLabel);
            processAction(actionButton, false);
            cacheStatus.setText(statusStopped);
            updateTitleBar();
      }
      controlPanelTab.repaint();
   }

   private void processAction(JButton button, boolean start)
   {
      button.setEnabled(!start);
      cacheStatusProgressBar.setVisible(start);
      cacheStatusProgressBar.setEnabled(start);
   }

   private String readContents(InputStream is) throws IOException
   {
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      String s;
      StringBuilder sb = new StringBuilder();
      while ((s = r.readLine()) != null)
      {
         sb.append(s);
         sb.append("\n");
      }
      return sb.toString();
   }

   private void startCache()
   {
      moveCacheToState(STARTING);

      // actually start the cache asynchronously.
      asyncExecutor.execute(new Runnable()
      {
         public void run()
         {
            if (cache == null)
            {
               URL resource = getClass().getClassLoader().getResource(cacheConfigFile);
               String contents;
               // update config file display
               if (resource != null)
               {
                  configFileName.setText(resource.toString());
               }
               else
               {
                  configFileName.setText(cacheConfigFile);
               }
               configFileName.repaint();

               try
               {
                  configFileContents.setText(readContents(resource == null ? new FileInputStream(cacheConfigFile) : resource.openStream()));
                  configFileContents.setEditable(false);
               }
               catch (Exception e)
               {
                  log.warn("Unable to open config file for display", e);
               }
               configFileContents.repaint();

               cache = new DefaultCacheFactory().createCache(cacheConfigFile);
               isUsingBuddyReplication = cache.getConfiguration().getBuddyReplicationConfig() != null && cache.getConfiguration().getBuddyReplicationConfig().isEnabled();
            }
            else
            {
               cache.start();
            }

            updateClusterTable(cache.getMembers());
            treeRefresher = new DataTreeRefresher(dataTree, cache, nodeDataTableModel);
            cache.addCacheListener(new CacheListener());
            moveCacheToState(STARTED);
         }
      });
   }

   private void stopCache()
   {
      moveCacheToState(CacheStatus.STOPPING);
      // actually stop the cache asynchronously
      asyncExecutor.execute(new Runnable()
      {
         public void run()
         {
            if (cache != null) cache.stop();
            moveCacheToState(STOPPED);
         }
      });
   }

   private void setCacheTabsStatus(boolean enabled)
   {
      int numTabs = mainPane.getTabCount();
      for (int i = 1; i < numTabs; i++) mainPane.setEnabledAt(i, enabled);
      panel1.repaint();
   }

   private void updateClusterTable(List<Address> members)
   {
      log.debug("Updating cluster table with new member list " + members);
      clusterDataModel.setMembers(members);
      updateTitleBar();
   }

   private void updateTitleBar()
   {
      String title = "JBoss Cache GUI Demo";
      if (cache != null && cache.getCacheStatus() == STARTED)
      {
         title += " (STARTED) " + cache.getLocalAddress() + " Cluster size: " + cache.getMembers().size();
      }
      else
      {
         title += " (STOPPED)";
      }
      frame.setTitle(title);
   }

   @org.jboss.cache.notifications.annotation.CacheListener
   public class CacheListener
   {
      @ViewChanged
      public void viewChangeEvent(ViewChangedEvent e)
      {
         updateClusterTable(e.getNewView().getMembers());
      }

      @BuddyGroupChanged
      public void buddyGroupChanged(BuddyGroupChangedEvent e)
      {
         clusterDataModel.setBuddies();
         treeRefresher.repaint();
      }

      @NodeModified
      public void nodeModified(NodeModifiedEvent e)
      {
         if (!e.isPre())
         {
            // only if this is the current node selected in the tree do we bother refreshing it
            if (nodeDataTableModel.getCurrentFqn() != null && nodeDataTableModel.getCurrentFqn().equals(e.getFqn()))
            {
               nodeDataTableModel.updateCurrentNode();
            }
         }
      }

      @NodeCreated
      public void nodeCreated(NodeCreatedEvent e)
      {
         if (!e.isPre())
         {
            final Fqn fqn = e.getFqn();
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  treeRefresher.addNode(fqn);
                  // only refresh if there are no more tasks queued up
                  if (asyncTaskQueue.isEmpty()) treeRefresher.repaint();
               }
            });
         }
      }

      @NodeMoved
      public void nodeMoved(NodeMovedEvent e)
      {
         if (!e.isPre())
         {
            final Fqn fqn = e.getTargetFqn();
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  // get all kids and add to the tree as well.
                  recursivelyAddNode(((CacheSPI) cache).peek(fqn, false));
                  // only refresh if there are no more tasks queued up
                  if (asyncTaskQueue.isEmpty()) treeRefresher.repaint();
               }

               private void recursivelyAddNode(NodeSPI<String, String> n)
               {
                  treeRefresher.addNode(n.getFqn());
                  for (NodeSPI<String, String> child : n.getChildrenDirect())
                     recursivelyAddNode(child);
               }

            });
         }
      }

      @NodeRemoved
      public void nodeRemoved(NodeRemovedEvent e)
      {
         if (!e.isPre())
         {
            final Fqn fqn = e.getFqn();
            asyncExecutor.execute(new Runnable()
            {
               public void run()
               {
                  treeRefresher.removeNode(fqn);
                  // only refresh if there are no more tasks queued up
                  if (asyncTaskQueue.isEmpty()) treeRefresher.repaint();
               }
            });
         }
      }

      // dont bother with node modified events since the tree GUI widget will refresh each node when it is selected.
   }

   public class ClusterTableModel extends AbstractTableModel
   {
      List<Address> members = new ArrayList<Address>();
      List<String> memberStates = new ArrayList<String>();

      public void setMembers(List<Address> members)
      {
         if (this.members != members)
         {
            this.members.clear();
            this.members.addAll(members);
         }

         List<Address> buddies = Collections.emptyList();
         if (isUsingBuddyReplication)
         {
            buddies = ((CacheSPI) cache).getBuddyManager().getBuddyAddresses();
            log.debug("Buddy addresses: " + buddies);
         }

         memberStates = new ArrayList<String>(members.size());
         for (Address a : members)
         {
            String extraInfo = "Member";
            // if this is the first member then this is the coordinator
            if (memberStates.isEmpty()) extraInfo += " (coord)";
            if (a.equals(cache.getLocalAddress()))
               extraInfo += " (me)";
            else if (buddies.contains(a))
               extraInfo += " (buddy)";
            memberStates.add(extraInfo);
         }

         fireTableDataChanged();
      }

      public void setBuddies()
      {
         setMembers(members);
      }

      public int getRowCount()
      {
         return members.size();
      }

      public int getColumnCount()
      {
         return 2;
      }

      public Object getValueAt(int rowIndex, int columnIndex)
      {
         switch (columnIndex)
         {
            case 0:
               return members.get(rowIndex);
            case 1:
               return memberStates.get(rowIndex);
         }
         return "NULL!";
      }

      public String getColumnName(int c)
      {
         if (c == 0) return "Member Address";
         if (c == 1) return "Member Info";
         return "NULL!";
      }
   }

   public class NodeDataTableModel extends AbstractTableModel
   {
      String[] keys = {};
      String[] values = {};
      private Fqn currentFqn;

      public void setData(Map<String, String> data)
      {
         keys = new String[data.size()];
         values = new String[data.size()];
         int i = 0;
         for (String key : data.keySet())
         {
            keys[i] = key;
            values[i] = data.get(key);
            i++;
         }

         fireTableDataChanged();
      }

      public int getRowCount()
      {
         return keys.length;
      }

      public int getColumnCount()
      {
         return 2;
      }

      public Object getValueAt(int rowIndex, int columnIndex)
      {
         switch (columnIndex)
         {
            case 0:
               return keys[rowIndex];
            case 1:
               return values[rowIndex];
         }
         return "NULL!";
      }

      public String getColumnName(int c)
      {
         if (c == 0) return "Key";
         if (c == 1) return "Value";
         return "NULL!";
      }

      public Fqn getCurrentFqn()
      {
         return currentFqn;
      }

      public void setCurrentFqn(Fqn currentFqn)
      {
         this.currentFqn = currentFqn;
      }

      public void updateCurrentNode()
      {
         setData(cache.getData(currentFqn));
      }
   }
}
TOP

Related Classes of org.jboss.cache.demo.JBossCacheDemo$ClusterTableModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.