• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 297
  • Last Modified:

null pointer exception -- object instantiation problem??

For what I have, please refer to:
http://www.experts-exchange.com/Programming/Programming_Languages/Java/Q_20805617.html

I have a problem where when I test the program with "type == 2" which goes through sendToOne() method in Server class, I get a NullPointerException at:

ServerThread.run() line94 -------------> server.sendToOne(distributeMessage.substring(2));
Server.sendToOne() line118 ------------>int r = scBack.write(buffer);

I declared a local ByteBuffer at the top of both methods to clear the buffer used in those methods.   Still, NullPointerException is thrown.   One possibility I think what's causing the error is the way I deal with the methods in DataHandler class, namely, addSocketChannel() and addUserInfo().   In particular, addSocketChannel() need to be invoked first to add an instance of SocketChannel into a LinkedList and this LinkedList is used when the latter addUserInfo() is called.   Since I call addUserInfo() at the Clinet constructor and addSocketChannel() at the Server constructor, the ordering of invokation might not seem to be a problem but the Server calls addSocketChannel() after there is an incoming request for connection meaning that by that time, Clinet is processed.   Also if I moved addSocketChannel() to right before the invokation of addUserInfo() in Clinet instead, there is no NullPointer but none of the test System.out outputs are printed.   Another possibility is that I have two instances of DataHandler object in Clinet and Server which they are both trying to access the same data.   Can this be a problem as well?   Since neither Client nor Server can access each other, if this causes a problem do I need to have a connection to a database to store the data which DataHandler is handling?   Even though it is indicated where the problem is caused, so far I find no effective method of tracking where in the transfer process or data storage something is going wrong.   Please give me a suggestion if someone can guide me in fixing this problem.   Thanks.  
0
skyblue01
Asked:
skyblue01
  • 11
  • 9
1 Solution
 
objectsCommented:
scBack must be null.
0
 
objectsCommented:
addUserInfo() is never called on the server, so privateChannles is never populated.
0
 
skyblue01Author Commented:
>addUserInfo() is never called on the server, so privateChannles is never populated.

The user info, such as username, groupname can only be retreived from the Clinet GUI.   So those information are not available for class Server (and cannot instantiate Client in Server since that would start another session for another user...)   This is the problem I was pointing out.   Is there a way to solve this while preserving the DataHandler class or this whole structure simply does not work?   Please give me your opinion.  
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
objectsCommented:
You need some way on the server to map which connections correspond to what user, perhaps the user details info should be passed from the client to the server when it connects.
0
 
skyblue01Author Commented:
But if Server is started first to listen for incoming connection, then in Clinet class if I want to have the user info passed from the Clinet to the Server when it connects, it will have another Server running, wouldn't it?  
0
 
objectsCommented:
I don't see why. Why do u think that?
0
 
skyblue01Author Commented:
By "passing from Client to Server", don't you mean that you'll do something like:

// Client
Server server = new Server(username, groupname, socketchannel...)

or

server.setInfo(username, groupname, socketchannel...)

Then for every instance of Ciient, an instance of Server will be created though I have one Server hanling all Client connections...
0
 
objectsCommented:
No I mean pass the details on the connection, like how you pass messages.
0
 
skyblue01Author Commented:
But then I'll need a place to store the data (such as DataHandler) for function like private chat, where one user specifies which other user it wants to talk to (which entails that when destination user is specified, it also have to get an instance of socketchannels, one from initiating client to the server, and another from destination client to server.   So I don't think just passing the user info would do it.   Also from the way I set up my classes, though Server can keep track of each individual socketchannels and perhaps store it in a Vector or LinkedList, as it receives the passed info, it has no way of identifying which info belongs to which channel...
0
 
objectsCommented:
When the server recieves a private message it needs some way to determine which connection to send that message out on. So whenever a connection is made it needs to provide details about the user that is making that connection.
0
 
objectsCommented:
>  it has no way of identifying which info belongs to which channel...

exactly you need to store that mapping.
0
 
skyblue01Author Commented:
Appending socketchannel at the end of message in processMessage method in Client, passed all the way to sendToOne method in Serever, which has some sort of Vector that keeps all socketchannels stored when its constructor is called, tokenize received message to get socketchannel, compare it to what's in the Vector from a beginning to an end, if matches, store the associated username and groupname which was also appended in the received message along with the matched socketchannel into a hashtable or something (keyed by socketchannel), then have everything stored in class Server, and finally write into the channel only the message part of the received message.   Would that work?   Although I'm using String message to be passed to sendToOne(), is it possible to have an object like socketchannel being appended to this data perhaps by changing this thing from String into Byte and then after decrypting it retreive the necessary object socketchannel and the string part of message?   Is such conversion or encryption/decryption of string+socketchannel into Byte and then back into string+socketchannel possible??
0
 
objectsCommented:
Not sure I understand what you mean, if you are saying pass the SocketChannel instance over the wire with the message then no.
0
 
skyblue01Author Commented:
What I mentioned above is the only way I could come up with.   I thought that was what you meant by "pass the details on the connection"...   Could you give me an example of what you mean by that?  
0
 
skyblue01Author Commented:
Or could you show me how it can be accomplished?
0
 
objectsCommented:
All you need to pass is whatever is needed to identify the user which I assume is the same as being passed with the message to identify who the message needs to go to.
0
 
skyblue01Author Commented:
Right, what identifies the user is its username and socketchannel.   So I was saying that I want to try doing something like below since data must be sent as bytes through a channel and String must be wrapped to get charbuffer.   But you said I can't do something like this...   Did you mean I can't do the concatenation of message and sc to form a string or this whole idea doesn't work?   I'm a little confused...

// in Clinet.java
private SocketChannel sc;
private String username;
private void processMessage(String message) { // message retrieved from the GUI
        try {
            if (type == 1)
                buffer = encoder.encode(CharBuffer.wrap(type + ":" + message + sc)); // <-------------------sc
            else if (type == 2 || type == 3)
                buffer = encoder.encode(CharBuffer.wrap(type + ":" + destUser + ":" + message + sc)); <--------sc

            int r = sc.write(buffer); // sends it to the server

            while (buffer.hasRemaining()) { // TEST
                int numWritten = sc.write(buffer); // sends it to the server
                buffer.compact(); // TEST
                buffer.flip(); // TEST
            }

            //System.out.println("numWritten at Client: " + numWritten); // TEST

            tf.setText(""); // clears the text input field
        } catch(IOException ie) { System.out.println(ie); }
    }
0
 
objectsCommented:
The server knows which channel a message is coming in from (as that is where it is reading it from), what it needs to know is what channel to send the message to.

Users need to identify themselves when they connect, otherwise the server has no idea which user is on which channel and thus no way to know what channel to send private messages on.

Does that make sense?
0
 
skyblue01Author Commented:
Hey objects, I solved the problem and came back to this question and figured out that what you told me was exactly right.   I couldn't understand what you meant since your explanation was kind of vague at that time.   I used a hashtable with a userinfo key and storing the received socket channel as its value -- i guess the term "mapping" you used was what confused me but please forgive me for not getting back to you...   And thanks for helping me out.  
0
 
objectsCommented:
I do have problems explaining myself sometimes.
Good to hear you got it solved :)

http://www.objects.com.au/staff/mick
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 11
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now