coordinating events


2004-03-02 05:51:30 AM
jbuilder10
Hi there,
I'm having difficulty trying to coordinate the sequence of events for
populating a JTree with data received from a server app. I'm so-o-o-o close
and yet no banana! It's proving to be very tricky processing. I could use
some help in trying to make this work properly. Perhaps you may understand
better as to why my efforts are being thwarted by the either the JTree
object or its DefaultTreeModel?
Here's the setup:
1) I have a server app that, when requested from the client app, will
provide a child count on any given directory node on the server. Also, it
will serve up the names of each child node for any given node upon request.
2) The client app contains a JTree object that I'm trying to initially
populate with the root node. Subsequently, the plan is to dynamically
populate any directory node in the JTree whenever the treeWillExpand( ... )
event is triggered as the user tries to expand on a node.
3) Throughout my code I have a number of System.out.println( ... )
statements so that I can see what sequence of events are taking place as the
client app makes requests to the server and receives replies back from the
server. Also, some println(...) statements in some key methods which you'll
see.
4) The sequence of events is supposed to go like so:
i) root node is created
ii) as the root node is passed as a parameter when creating the JTree
object
the getChildCount( ) method of the root node [type DefaultTreeNode
extends DefaultMutableTreeNode ]
is called.
public int getChildCount()
{
if (!hasChildren)
{
defineChildNodes();
}
return(super.getChildCount());
}
iii) Since the root node initially has no children, getChildCount( )
then calls the method
defineChildNodes( ).
protected void defineChildNodes()
{
hasChildren = true;
ref.requestChildCountFromServer(this);
}
As you can see, defineChildNodes( ) simply sets the flag
hasChildren to true then
calls a method requestChildCountFromServer(this) which exists in a
class called Response
referred here by the variable "ref". Also in the Response class
there exists the method
populateTree( ) which initially created the root node and JTree
objects:
protected void populateTree(String NodeName)
{
//System.out.println("Entering populatTree() method");
//This could take a while, so change the cursor icon
//ref.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try
{
String separator = "";
if(ref.serverOS.equals("Windows"))
separator = "\\";
else
separator = "/";
rootNode = new DefaultTreeNode(NodeName, true, separator);
expandingNode = rootNode;
String rootPath = getLeadingPath(ref.rootPath);
rootNode.setLeadingPath(rootPath);
rootNode.setResponseReference(this);
jTree1 = new JTree(rootNode);
jTree1.setRootVisible(true);
jTree1.setShowsRootHandles(true);
jTree1.collapseRow(0);
MouseListener popupListener = new PopupListener(ref);
jTree1.addMouseListener(popupListener);
//Listen to our own expand/collapse events to keep the labels in
sync
jTree1.addTreeWillExpandListener(this);
}
catch(Exception e){System.out.println("Exception in populateTree()
method"); e.printStackTrace();return;}
....
....
}
iv) The requestChildCountFromServer( ) method then makes a request to
the server app for
the child count for the root node.
v) I have a separate thread running that listens for all responses
from the server
called ResponseListener. In its run( ) method I have the
following code:
else if(connected == ref.ref.SENDING_CHILDCOUNT)
{
System.out.println("Received message: ReceivingChildCount");
ref.expandingNode.numChildren = input.readInt();
//expandingNode.setReceivedChildCount(true);
ref.ref.imageLabel.setIcon(ref.ref.blank);
ref.ref.textLabel.setText("");
}
When the root node was originally created I set a reference to it
using a variable
named expandingNode. Here you can see that the root node's
instance variable
named numChildren is set to a value read in by the DataInputStream
object
named input.
vi) The requestChildCountFromServer( ) method in turn calls another
method in the
Response class named RequestChildrenFromServer(String path).
RequestChildrenFromServer(String path) method requests from the
server the names
of all the child nodes for the root node.
vii) ResponseListener then receives a response from the server:
else if(connected == ref.ref.SENDING_TREE_DATA)
{
System.out.println("Received message: SendingTreeData");
ref.expandingNode.TreeDataIncoming = true;
ref.expandingNode.ReceiveChildrenFromServer(input);
ref.ref.imageLabel.setIcon(ref.ref.blank);
ref.ref.textLabel.setText("");
}
Here you can see that the root nodes method named
ReceiveChildrenFromServer(input) is then called
while passing it a reference to the DataInputStream so that the
method can
read in the names of the child nodes as they come in over the
wire.
viii) The root node's method ReceiveChildrenFromServer(input) then
begins receiving the
names of each child node, creates a new DefaultTreeNode object
for each child node
and adds it to the root node, seen below:
protected void ReceiveChildrenFromServer(DataInputStream input)
{
System.out.println("Entering ReceiveChildrenFromServer()");
DefaultTreeNode child = null;
String name = "";
try
{
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//System.out.println("numChildren = " + numChildren);
int nodeType = 0;//default
//iterate through each of the children as they come in
//from the server.
for(int i = 0; i < numChildren; i++)
{
name = input.readUTF(); //get the name
System.out.println("child node: " + name);
child = new DefaultTreeNode(name); //create a new
child node
//determine if this node is a directory
//or a file. Empty directories are denoted
//as having (nodeType == -1)
nodeType = input.readInt();
//System.out.println("node type: " + nodeType);
if(nodeType == 0)
{
//Since a file is a leaf node
//we won't be needing to continue
//reading in nodes for it.
child.setResponseReference(ref);
child.setAllowsChildren(false);
child.setHasChildren(false);
child.setLeadingPath(getWholeServerPath());
if(ref.ref.serverOS.equals("Windows"))
child.setSeparator("\\");
else
child.setSeparator("/");
}
else if(nodeType == -1)
{
child.setResponseReference(ref);
child.setAllowsChildren(true); //It's an empty
directory
child.setHasChildren(false);
child.setLeadingPath(getWholeServerPath());
if(ref.ref.serverOS.equals("Windows"))
child.setSeparator("\\");
else
child.setSeparator("/");
}
else
{
child.setResponseReference(ref);
child.setAllowsChildren(true); //It's a directory
with child nodes
child.setHasChildren(true);
child.setLeadingPath(getWholeServerPath());
if(ref.ref.serverOS.equals("Windows"))
child.setSeparator("\\");
else
child.setSeparator("/");
}
this.insert(child,i);
}//end for loop
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}//end try
catch(IOException ioe){ioe.printStackTrace();}
catch(NullPointerException npe){npe.printStackTrace();}
}//end method
IT IS HERE THAT I RUN INTO PROBLEMS!!!!
All the code you see compiles fine. What I found annoying is that, at
run-time, the sequence of events were as I depict them here until I start
reading in the names of the childnodes with the
ReceiveChildrenFromServer(...) method. While it is going through its for
loop, mysteriously the method getChildCount( ) is called again, which in
turn calls defineChildNodes( ), which in turn calls
requestChildCountFromServer(...), which interrupts the processing of the for
loop in ReceiveChildrenFromServer(...) . Here is the read out from the
console to prove it:
***************************************
Entering requestChildCountFromServer
waiting for response...
checking...
Received message: ReceivingChildCount
checking...
got ChildCount: 26 <<<Root node has 26 child nodes
Entering RequestChildrenFromServer()
path is: C:\JavaProjects
Finished calling server for children
Received message: SendingTreeData
Entering ReceiveChildrenFromServer()
checking for tree data ...
child node: AssignmentServer <<<<ReceiveChildrenFromServer(...)
method begins reading in names
child node: AssignmentSubmitter
child node: Borland
child node: ClientServerJTreeProject
child node: DBJavaBean
child node: DirAdmin.bak
Entering requestChildCountFromServer <<<This method is called by
defineChildNodes( ) which was
called by getChildCount( )
waiting for response...
checking...
checking...
Node Expanding.
checking...
checking...
got ChildCount: 0 <<< Don't know
why this is reading zero. It should be 26
child node: DirectoryAdministratorProject <<<For loop from
ReceiveChildrenFromServer(...) method
resumes reading in names
child node: EZSmtp
child node: Icon Editor
child node: images
child node: IniFileProject
child node: J2exe
child node: JCalculator
child node: JGridProject
child node: JSlideShow
child node: MSSTextEditorProject
child node: MySQL_JDBC
child node: PersonalNetSearchProject
child node: Print_Preview
child node: PropertiesFileAccessExample
child node: Sample_EBusiness
child node: SharewareProject
child node: SystemTreeProject
child node: TestProgram
child node: Thread_Pooling
child node: ZeroG
Received message: ReceivingChildCount
*****************************************
Ultimately, I wind up with a root node being displayed in the JTree that
only has maybe five or six child nodes displayed when there should be 26
child nodes.
For further clarity here are the methods requestChildCountFromServer(...)
and RequestChildrenFromServer(...):
public void requestChildCountFromServer(DefaultTreeNode node)
{
System.out.println("Entering requestChildCountFromServer");
String name = "";
try
{
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
output.writeInt(ref.PATH);
output.flush();
output.writeUTF(node.getWholeServerPath());
output.flush();
output.writeInt(ref.REQUEST_CHILD_COUNT);
output.flush();
System.out.println("waiting for response...");
timer1 = new ChildCountTimer(node);
timer1.start();
timer1.join();
System.out.println("got ChildCount: " + node.numChildren);
if(node.numChildren>0)
{
//NodeExpanding = false; //reset
RequestChildrenFromServer(node.getWholeServerPath());
//Set up TreeDataTimer so that we know we have a
//response from the server.
timer2 = new TreeDataTimer(node);
timer2.start();
timer2.join();
}
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
catch(InterruptedException ie){}
catch(IOException ioe){ioe.printStackTrace();}
catch(NullPointerException npe){npe.printStackTrace();}
}
protected void RequestChildrenFromServer(String path)
{
System.out.println("Entering RequestChildrenFromServer()");
//Request Children from server
try
{
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
output.writeInt(ref.PATH);
output.flush();
System.out.println("path is: " + path);
output.writeUTF(path);
output.flush();
//Sending REQUEST_CHILDREN should cause a response
//from the server: SENDING_TREE_DATA
output.writeInt(ref.REQUEST_CHILDREN);
output.flush();
//ref.ref.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
catch(IOException ioe){ioe.printStackTrace();}
System.out.println("Finished calling server for children");
}
I realize this post is rather lengthy, however, I didn't know how else to
explain my dilemma with this project. If you need more information, just
ask.
Please advise,
Alan