/*
* JBoss, Home of Professional Open Source
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
/*
* Copyright (C) 1998, 1999, 2000,
*
* Arjuna Solutions Limited,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: OTM.java 2342 2006-03-30 13:06:17Z $
*/
package com.arjuna.ats.arjuna.tools;
import java.awt.Dimension;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.arjuna.objectstore.RecoveryStore;
import com.arjuna.ats.arjuna.objectstore.StateStatus;
import com.arjuna.ats.arjuna.objectstore.StoreManager;
import com.arjuna.ats.arjuna.state.InputObjectState;
import com.arjuna.ats.internal.arjuna.common.UidHelper;
import com.arjuna.common.util.propertyservice.PropertiesFactory;
/*
* Currently only looks at this machine.
*/
class DirEntry
{
public DirEntry()
{
node = null;
fullPathName = null;
present = false;
}
public DirEntry(DefaultMutableTreeNode n, String s)
{
node = n;
fullPathName = s;
present = true;
}
public DefaultMutableTreeNode node;
public String fullPathName;
public boolean present;
};
class MonitorThread extends Thread
{
public MonitorThread(OTM arg, long timeout)
{
otm = arg;
sleepTime = timeout;
}
public void run ()
{
for (;;)
{
try
{
Thread.sleep(sleepTime);
}
catch (Exception e)
{
}
otm.updateTransactions();
}
}
private OTM otm;
private long sleepTime;
};
public class OTM extends JSplitPane
{
public OTM()
{
super(HORIZONTAL_SPLIT);
String localHost = null;
try
{
InetAddress myAddress = InetAddress.getLocalHost();
localHost = myAddress.getHostName();
}
catch (UnknownHostException e)
{
localHost = "LocalHostUnknown";
}
_machines.addElement(localHost);
localHost = null;
// Create the nodes.
topMachine = new DefaultMutableTreeNode("Registered machines.");
topTran = new DefaultMutableTreeNode("Running transactions.");
createNodes(topMachine);
// Create a tree that allows one selection at a time.
tree = new JTree(topMachine);
transactions = new JTree(topTran);
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
// Listen for when the selection changes.
MouseListener ml = new MouseAdapter()
{
public void mouseClicked (MouseEvent e)
{
int selRow = tree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if (selRow != -1)
{
if (e.getClickCount() == 2)
{
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK)
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath
.getPathComponent(selRow);
if (node.isLeaf())
{
getTransactions(node);
}
else
removeTransactions(); //modifyTransactionView();
}
}
if (e.getClickCount() == 1)
{
if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
removeTransactions();
}
}
}
};
tree.addMouseListener(ml);
// Create the scroll pane and add the tree to it.
JScrollPane treeView = new JScrollPane(tree);
JScrollPane tranView = new JScrollPane(transactions);
// Add the scroll panes to this panel.
add(treeView);
add(tranView);
Dimension minimumSize = new Dimension(100, 100);
treeView.setMinimumSize(minimumSize);
tranView.setMinimumSize(minimumSize);
/*
* setDividerLocation(300); //XXX: ignored! bug 4101306 workaround for
* bug 4101306:
*/
treeView.setPreferredSize(new Dimension(200, 200));
setPreferredSize(new Dimension(500, 300));
}
@SuppressWarnings("unchecked")
public synchronized void updateTransactions ()
{
if (scanningNode != null)
{
DefaultMutableTreeNode top = (DefaultMutableTreeNode) topTran
.getFirstChild();
DefaultTreeModel model = (DefaultTreeModel) transactions.getModel();
try
{
RecoveryStore recoveryStore = StoreManager.getRecoveryStore();
InputObjectState types = new InputObjectState();
startSweep();
if (recoveryStore.allTypes(types))
{
String fullPathName = null;
boolean found = false;
try
{
boolean endOfList = false;
DefaultMutableTreeNode currentNode = null;
DefaultMutableTreeNode currentRoot = top;
while (!endOfList)
{
fullPathName = types.unpackString();
if (fullPathName.compareTo("") == 0)
endOfList = true;
else
{
found = true;
InputObjectState uids = new InputObjectState();
String nodeName = stripName(fullPathName);
boolean added = false;
currentNode = findNode(fullPathName);
if (currentNode == null)
{
currentNode = new DefaultMutableTreeNode(
nodeName);
addDirectory(currentNode, fullPathName);
currentRoot.add(currentNode);
/*
* New, so update view.
*/
int i[] = new int[1];
i[0] = currentRoot.getChildCount() - 1;
model.nodesWereInserted(currentRoot, i);
added = true;
}
currentRoot = findRoot(top, currentNode);
if (added)
currentRoot.add(currentNode);
if (recoveryStore.allObjUids(fullPathName, uids))
{
Uid theUid = new Uid(Uid.nullUid());
try
{
boolean endOfUids = false;
boolean first = true;
boolean haveUids = false;
while (!endOfUids)
{
theUid = UidHelper.unpackFrom(uids);
if (theUid.equals(Uid.nullUid()))
{
if (!haveUids)
{
if (emptyDirectory(currentNode))
{
currentNode
.removeAllChildren();
model
.nodeChanged(currentNode);
}
}
endOfUids = true;
}
else
{
haveUids = true;
if (first)
{
currentNode
.removeAllChildren();
first = false;
}
DefaultMutableTreeNode tranID = new DefaultMutableTreeNode(
theUid.stringForm());
tranID
.add(new DefaultMutableTreeNode(
new String(
"status: "
+ statusToString(recoveryStore
.currentState(
theUid,
fullPathName)))));
currentNode.add(tranID);
added = true;
}
}
}
catch (Exception e)
{
// end of uids!
}
if (added)
model.nodeChanged(currentNode);
}
}
/*
* To show that we did some work, write some text.
*/
if (!found)
currentRoot.add(emptyTx);
}
}
catch (Exception e)
{
// end of list!
}
}
try
{
endSweep();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
catch (Exception e)
{
System.err.println(e);
}
}
}
private boolean emptyDirectory (DefaultMutableTreeNode node)
{
DefaultMutableTreeNode child = (DefaultMutableTreeNode) node
.getFirstChild();
if (child != null)
{
DefaultMutableTreeNode status = (DefaultMutableTreeNode) child
.getFirstChild();
if (status != null)
return status.isLeaf();
}
return true;
}
private void createNodes (DefaultMutableTreeNode topMachine)
{
int number = _machines.size();
DefaultMutableTreeNode machine = null;
if (number == 0)
{
topMachine
.add(new DefaultMutableTreeNode("No machines registered."));
}
else
{
String machineName = null;
for (int i = 0; i < number; i++)
{
machineName = (String) _machines.elementAt(i);
machine = new DefaultMutableTreeNode(machineName);
topMachine.add(machine);
}
}
}
private void modifyTransactionView ()
{
if (transactions.isCollapsed(1))
transactions.expandRow(1);
else
transactions.collapseRow(1);
}
private void removeTransactions ()
{
int count = transactions.getRowCount();
for (int i = count; i > 0; i--)
{
transactions.collapseRow(i);
transactions.removeSelectionRow(i);
}
topTran.removeAllChildren();
transactions.repaint();
_dirs = new Vector();
DefaultTreeModel model = (DefaultTreeModel) transactions.getModel();
model.reload();
transactions.repaint();
scanningNode = null;
}
@SuppressWarnings("unchecked")
private synchronized void getTransactions (
DefaultMutableTreeNode machineName)
{
removeTransactions();
scanningNode = machineName;
DefaultMutableTreeNode top = new DefaultMutableTreeNode(scanningNode);
try
{
RecoveryStore recoveryStore = StoreManager.getRecoveryStore();
InputObjectState types = new InputObjectState();
if (recoveryStore.allTypes(types))
{
String fullPathName = null;
boolean found = false;
try
{
boolean endOfList = false;
DefaultMutableTreeNode currentNode = null;
DefaultMutableTreeNode currentRoot = top;
topTran.add(currentRoot);
while (!endOfList)
{
fullPathName = types.unpackString();
if (fullPathName.compareTo("") == 0)
endOfList = true;
else
{
found = true;
InputObjectState uids = new InputObjectState();
String nodeName = stripName(fullPathName);
currentNode = new DefaultMutableTreeNode(nodeName);
addDirectory(currentNode, fullPathName);
currentRoot = findRoot(top, currentNode);
currentRoot.add(currentNode);
if (recoveryStore.allObjUids(fullPathName, uids))
{
Uid theUid = new Uid(Uid.nullUid());
try
{
boolean endOfUids = false;
while (!endOfUids)
{
theUid = UidHelper.unpackFrom(uids);
if (theUid.equals(Uid.nullUid()))
endOfUids = true;
else
{
DefaultMutableTreeNode tranID = new DefaultMutableTreeNode(
theUid.stringForm());
tranID
.add(new DefaultMutableTreeNode(
new String(
"status: "
+ statusToString(recoveryStore
.currentState(
theUid,
fullPathName)))));
currentNode.add(tranID);
}
}
}
catch (Exception e)
{
// end of uids!
}
}
}
/*
* To show that we did some work, write some text.
*/
if (!found)
currentRoot.add(emptyTx);
}
}
catch (Exception e)
{
// end of list!
}
}
}
catch (Exception e)
{
System.err.println(e);
}
DefaultTreeModel model = (DefaultTreeModel) transactions.getModel();
model.reload();
transactions.repaint();
}
private void startSweep ()
{
int number = _dirs.size();
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
dirEntry.present = false;
}
}
}
private void endSweep ()
{
int number = _dirs.size();
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
{
if (!dirEntry.present)
{
DefaultMutableTreeNode top = (DefaultMutableTreeNode) topTran
.getFirstChild();
DefaultTreeModel model = (DefaultTreeModel) transactions
.getModel();
DefaultMutableTreeNode root = findRoot(top,
dirEntry.node);
int index = root.getIndex(dirEntry.node);
int j[] = new int[1];
Object o[] = new Object[1];
j[0] = root.getIndex(dirEntry.node);
o[0] = dirEntry.node;
root.remove(dirEntry.node);
model.nodesWereRemoved(root, j, o);
_dirs.removeElement(dirEntry);
dirEntry.node = null;
j = null;
o = null;
}
}
}
}
}
private synchronized DefaultMutableTreeNode findNode (String fullPathName)
{
if (fullPathName != null)
{
int number = _dirs.size();
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
{
if (dirEntry.fullPathName.compareTo(fullPathName) == 0)
{
/*
* Found entry in new list, so mark it as present.
*/
dirEntry.present = true;
return dirEntry.node;
}
}
}
}
}
return null;
}
private synchronized DefaultMutableTreeNode findRoot (
DefaultMutableTreeNode top, DefaultMutableTreeNode curr)
{
DefaultMutableTreeNode root = top;
if (curr != null)
{
int number = _dirs.size();
String name = fullNodeName(curr);
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
{
DefaultMutableTreeNode node = dirEntry.node;
String dirName = dirEntry.fullPathName;
if ((name.indexOf(dirName) != -1) && (node != curr))
root = node;
}
}
}
}
return root;
}
private void addDirectory (DefaultMutableTreeNode node, String path)
{
_dirs.addElement(new DirEntry(node, path));
}
private void removeDirectory (String path)
{
Enumeration elements = _dirs.elements();
while (elements.hasMoreElements())
{
DirEntry e = (DirEntry) elements.nextElement();
if (e.fullPathName.compareTo(path) == 0)
{
_dirs.removeElement(e);
return;
}
}
}
private String fullNodeName (DefaultMutableTreeNode curr)
{
String root = "StateManager";
if (curr != null)
{
int number = _dirs.size();
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
{
if (dirEntry.node == curr)
return dirEntry.fullPathName;
}
}
root = (String) curr.getUserObject();
}
}
return root;
}
private String stripName (String name)
{
String root = null;
if (name != null)
{
int number = _dirs.size();
if (number != 0)
{
for (int i = 0; i < number; i++)
{
DirEntry dirEntry = (DirEntry) _dirs.elementAt(i);
if (dirEntry != null)
{
DefaultMutableTreeNode node = dirEntry.node;
String dirName = dirEntry.fullPathName;
int subString = name.indexOf(dirName);
if ((subString != -1) && (name.compareTo(dirName) != 0))
{
root = name.substring(subString + dirName.length()
+ 1);
}
}
}
}
if (root == null)
root = name;
}
else
root = "StateManager";
return root;
}
private void printChildren (DefaultMutableTreeNode currentNode)
{
if (currentNode != null)
{
Enumeration children = currentNode.children();
if (children != null)
{
String name = (String) currentNode.getUserObject();
System.out.println("Node: " + name);
while (children.hasMoreElements())
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) children
.nextElement();
name = (String) node.getUserObject();
System.out.println("\tChild: " + name);
}
}
}
}
private static String statusToString (int status)
{
switch (status)
{
case StateStatus.OS_COMMITTED:
return "StateStatus.OS_COMMITTED";
case StateStatus.OS_UNCOMMITTED:
return "StateStatus.OS_UNCOMMITTED";
case StateStatus.OS_HIDDEN:
return "StateStatus.OS_HIDDEN";
case StateStatus.OS_COMMITTED_HIDDEN:
return "StateStatus.OS_COMMITTED_HIDDEN";
case StateStatus.OS_UNCOMMITTED_HIDDEN:
return "StateStatus.OS_UNCOMMITTED_HIDDEN";
default:
case StateStatus.OS_UNKNOWN:
return "StateStatus.OS_UNKNOWN";
}
}
public static void main (String[] args)
{
Uid u = new Uid();
String timeout = PropertiesFactory.getDefaultProperties().getProperty(
pollingTimeout);
if (timeout != null)
{
try
{
sleepTime = Long.parseLong(timeout); // is it a digit?
}
catch (NumberFormatException e)
{
System.err.println("Error - specified timeout " + timeout
+ " is invalid!");
System.exit(0);
}
}
/*
* Create a window. Use JFrame since this window will include
* lightweight components.
*/
JFrame frame = new JFrame("OTM Transaction Monitor");
WindowListener l = new WindowAdapter()
{
public void windowClosing (WindowEvent e)
{
System.exit(0);
}
};
frame.addWindowListener(l);
OTM otm = new OTM();
frame.getContentPane().add("Center", otm);
frame.pack();
frame.show();
if (sleepTime != -1)
{
MonitorThread thread = new MonitorThread(otm, sleepTime);
thread.start();
}
}
private static Vector _machines = new Vector();
private static Vector _dirs = new Vector();
private static DefaultMutableTreeNode topMachine = null;
private static DefaultMutableTreeNode topTran = null;
private static DefaultMutableTreeNode scanningNode = null;
private static DefaultMutableTreeNode emptyTx = new DefaultMutableTreeNode(
"No transactions.");
private static JTree tree = null;
private static JTree transactions = null;
private static String pollingTimeout = "MONITORING_TIMEOUT";
private static long sleepTime = -1;
};