DefaultTreeModel Not Being Received Correctly

Hi There,

I am writing an application in which I am using a JTree to display a DefaultTreeModel which initially contains one parent TreeNode with about 2200 TreeNodes as children, i.e. two levels of nodes. As the user clicks on each of the children, that TreeNode's children are lazy-loaded into the TreeModel, and the JTree is re-painted. That all works.

I am currently implementing the cache by sending the TreeModel to the server each time a new child is lazy-loaded in the client using Sockets. I have tested the object that is being written to the ObjectOutputStream, and that is the correct TreeModel. However, when I test the object that is received through the ObjectInputStream on the server side, it reverts back to the previous version of the TreeModel - i.e. it is not receiving the most up-to-date version. I really don't know why. I have experimented with putting objectOutputStream.flush() in various places and that doesn't seem to make a difference.

This is the method on the client side:

privatevoid writeToServer(ObjectOutputStream oos, RequestProtocolInterface request)

{

try

{

oos.writeObject(request);//this request object contains the most up-to-date version of DefaultTreeModel

oos.flush();

}

catch(IOException e)

{

System.out.println(e.toString());

}

}

This is the run() method on the server side thread:

publicvoid run()

{

RequestProtocolInterface request =null;

Object readObject =null;

while(connected)

{

try

{

readObject = ois.readObject();//for some reason, this does not contain the most up-to-date version

request = (RequestProtocolInterface)readObject;

request.process(this);

}

catch(Exception e)

{

closeConnection();

}

}

}

If you need more information or code, please let me know. I would appreciate any help.

[2798 byte] By [RoxyLJa] at [2007-10-3 8:10:03]
# 1
ObjectOutputStream.writeUnshared()
ejpa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 2
I've replaced writeObject() with writeUnshared(), and that has changed the behaviour, but still hasn't fixed it. Its behaviour is so erratic that I can't even work out what the sequence of events is that is common to the times that the most up-to-date TreeModel is received.
RoxyLJa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 3
Is there anyone that can offer any further help? I would really appreciate it. I'm quite stuck...
RoxyLJa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 4

You haven't said what your current problem is. writeUnshared() fixes the problem with the old data being read as per its specification; you could also try ObjectOutputStream.reset() and/or ObjectInputStream.readUnshared(). All these are just different approaches to the same issue which is that object streams have 'memory', which in your case you don't want.

ejpa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 5

Hi ejp,

I think this topic might have been more appropriate for the Networking forum. Oh well.

Anyway, sorry for the delay in replying. I've been testing it and trying to find the reason behind why it's not writing the TreeModel correctly, but honestly have not been able to come up with more of an answer. The client is sending the correct TreeModel, but the server is not receiving the correct one. I really don't know why.

I have written a little test program to illustrate the problem. To keep it simple I have not added any methods to close streams or connections. The server throws a socket exception when the first client is run, but on every subsequent run of the client, the problem I'm having is duplicated.

The client's output (on every run after the first) is:

On write 1, the root had 3 children.

On write 2, the root had 4 children.

This is correct. However, the client's output (on every run after the first) is:

On read 1, the root had 3 children.

On read 2, the root had 3 children.

...but the output that I actually want the server to have is:

On read 1, the root had 3 children.

On read 2, the root had 4 children.

Here is the code:

Server.java

import java.net.*;

import java.sql.*;

public class Server extends Thread

{

private final String USERNAME = "JohnDoe";//replace with own username

private final String PASSWORD = "MyPassword";//replace with own password

private final String DATABASE = "MY_DB";//replace with own database

private final String URL = "jdbc:odbc:" + DATABASE;

private final int PORT = 5000;//replace with available port if necessary

private final String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";

private ServerSocket serverSocket = null;

private Connection connection = null;

public static void main(String[] args)

{

try

{

new Server();

}

catch (Exception e)

{

System.out.println(e.toString());

}

}

public Server() throws Exception

{

try

{

Class.forName(DRIVER);

connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);

serverSocket = new ServerSocket(PORT);

}

catch (Exception e)

{

System.out.println(e.toString());

}

this.start();

}

public void run()

{

while(true)

{

try

{

System.out.println("Waiting for client connections...");

Socket client = serverSocket.accept();

System.out.println("Accepted a connection from client " + client.getInetAddress().getLocalHost() + ".");

new ServerThread(client, connection);

}

catch(Exception e)

{

System.out.println(e.toString());

}

}

}

}

ServerThread.javaimport java.io.*;

import java.net.Socket;

import java.sql.Connection;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.DefaultTreeModel;

public class ServerThread extends Thread

{

private ObjectInputStream ois = null;

private Connection conn = null;

private Socket sock = null;

public ServerThread(Socket sock, Connection conn)

{

this.sock = sock;

try

{

InputStream in = this.sock.getInputStream();

ois = new ObjectInputStream(in);

}

catch (Exception e)

{

System.out.println(e.toString());

}

this.start();

}

public void run()

{

int i = 1;

readAnObject(i);

i++;

readAnObject(i);

}

public void readAnObject(int i)

{

Object readObject = null;

try

{

readObject = ois.readObject();

DefaultTreeModel model = (DefaultTreeModel)readObject;

DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();

System.out.println("On read " + i + ", the root had " + root.getChildCount() + " children.");

}

catch (Exception e)

{

System.out.println(e.toString());//An (irrelevant?) error is thrown here when the first client is run.

}

}

}

Client.javaimport java.io.*;

import java.net.Socket;

import javax.swing.JTree;

import javax.swing.tree.*;

public class Client

{

private final String SERVER = "MyComputer";//replace with the name of the computer being used as the server

private final int PORT = 5000;//ensure this is the same as the PORT specified in Server.java

private ObjectOutputStream oos = null;

private Socket sock = null;

public static void main(String[] args)

{

new Client();

}

public Client()

{

try

{

sock = new Socket(SERVER, PORT);

OutputStream out = sock.getOutputStream();

oos = new ObjectOutputStream(out);

}

catch (Exception e)

{

System.out.println(e.toString());

}

JTree tree = new JTree();

TreeModel model = tree.getModel();

DefaultMutableTreeNode anotherNode = new DefaultMutableTreeNode("AnotherNode");

DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();

int i = 1;

writeTreeModel(model, i);

i++;

root.add(anotherNode);

writeTreeModel(model, i);

}

private void writeTreeModel(TreeModel model, int i)

{

DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();

System.out.println("On write " + i + ", the root had " + root.getChildCount() + " children.");

try

{

oos.writeUnshared((Object)model);//have also tried oos.writeObject((Object)model) here

oos.flush();//have experimented with where to put this

}

catch(Exception e)

{

System.out.println(e.toString());

}

}

}

To test this program:

1. Run Server.java

2. Run Client.java - the first run produces a (possibly irrelevant) SocketException

3. Run Client.java again

On step 3, this is what happens:

1. The client creates a new sample JTree instance.

2. The JTree's model is retrieved.

3. The number of children of the root of the model is displayed (3).

4. The model is written to the server.

5. The server receives the model with the correct number of children of the root, as displayed by its output (3).

6. A new node is added to the root node of the model in the client.

7. The number of children of the root of the model is displayed (4).

8. The model is written to the server.

9. The server receives the model with the incorrect number of children of the root, as displayed by its output (still 3 instead of 4).

Do you have any idea as to why this problem is occurring?

Thanks. :)

RoxyLJa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 6
Hmm. Looking at the received hashcodes, apparently writeUnshared() is giving you a new 'model' object but the same old same old 'root' object. Interesting trap, didn't know that.This works:oos.reset();oos.writeObject(model);
ejpa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...
# 7
Excellent! Thanks, ejp!
RoxyLJa at 2007-7-15 3:14:23 > top of Java-index,Core,Core APIs...