0

I am making a simple client-server messenger pair with Sockets and JSwing, and I have recently run into a StackOverflow error. I know(or at least think) that it's caused by a recursive functon(which I don't think I have, but I may) that doesn't have a correct termination condition(does this mean like a return; in a switch statement?) Here's some of the error(since it's a StackOverflow, it repeats itself, of course)

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.util.HashMap.getEntry(Unknown Source)
at java.util.HashMap.get(Unknown Source)
at sun.awt.AppContext.get(Unknown Source)
at com.sun.java.swing.SwingUtilities3.getDelegateRepaintManager(Unknown Source)
at javax.swing.RepaintManager.getDelegate(Unknown Source)
at javax.swing.RepaintManager.addDirtyRegion(Unknown Source)
at javax.swing.JComponent.repaint(Unknown Source)
at java.awt.Component.repaint(Unknown Source)
at javax.swing.JComponent.setBackground(Unknown Source)
at javax.swing.LookAndFeel.installColors(Unknown Source)
at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
at javax.swing.JComponent.setUI(Unknown Source)
at javax.swing.JPanel.setUI(Unknown Source)
at javax.swing.JPanel.updateUI(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JPanel.<init>(Unknown Source)
at javax.swing.JRootPane.createGlassPane(Unknown Source)
at javax.swing.JRootPane.<init>(Unknown Source)
at javax.swing.JFrame.createRootPane(Unknown Source)
at javax.swing.JFrame.frameInit(Unknown Source)
at javax.swing.JFrame.<init>(Unknown Source)
at Socket_Swing_Database_Test.SocketManager.<init>(SocketManager.java:9)
at Socket_Swing_Database_Test.ClientSwing.<init>(ClientSwing.java:6)
at Socket_Swing_Database_Test.SocketManager.<init>(SocketManager.java:10)
at Socket_Swing_Database_Test.ClientSwing.<init>(ClientSwing.java:6)
at Socket_Swing_Database_Test.SocketManager.<init>(SocketManager.java:10)
at Socket_Swing_Database_Test.ClientSwing.<init>(ClientSwing.java:6)
at Socket_Swing_Database_Test.SocketManager.<init>(SocketManager.java:10)

My code:

public class ClientMain extends JFrame {
private SocketManager sm = new SocketManager();

public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            ClientSwing window = new ClientSwing();
            window.setVisible(true);

        }
    });
}

public void run() {
    sm = new SocketManager();

    Thread thread = new Thread(sm);
    thread.run();
}

}

ClientSwing:

public class ClientSwing extends JFrame implements Runnable {
public SocketManager socketmanager = new SocketManager();

public final int NULL = 0;
public final int DISCONNECTED = 1;
public final int DISCONNECTING = 2;
public final int BEGIN_CONNECT = 3;
public final int CONNECTED = 4;
public int connectionStatus = socketmanager.connectionStatus;

public JPanel panel, statusBar;
public JTextArea textArea;
public JTextField textField, statusColor, usernameField;
public JLabel statusField;
public JMenuBar menuBar;
public JButton connectButton, disconectButton;

public int WIDTH = 640;
public int HEIGHT = 480;

public ClientSwing() {
    super("Client");

    panel = new JPanel();
    panel.setLayout(null);



    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setSize(WIDTH, HEIGHT);
    setResizable(true);
    setJMenuBar(menuBar);
}

@Override
public void run() {
    switch(connectionStatus) {
    case DISCONNECTED:

        break;

    case DISCONNECTING:

        break;

    case CONNECTED:

        break;

    case BEGIN_CONNECT:

        break;
    }
}

public void invoke(Runnable runnable) {
    SwingUtilities.invokeLater(runnable);

}

}

SocketManager:

public class SocketManager extends JFrame implements Runnable {
public ClientSwing cs = new ClientSwing();

public final int NULL = 0;
public final int DISCONNECTED = 1;
public final int DISCONNECTING = 2;
public final int BEGIN_CONNECT = 3;
public final int CONNECTED = 4;

public final String statusMessages[] = {
    " Error! Could not connect", " Disconnected",
    " Disconnecting...", " Connceting...", " Connected"
};

public final String END_CHAT_SESSION = new Character((char)0).toString();

public String hostIP = "localhost";
public int port = 2484;
public int connectionStatus = DISCONNECTED;
public StringBuffer toAppend = new StringBuffer("");
public StringBuffer toSend = new StringBuffer("");
public String statusString = statusMessages[connectionStatus];

public Socket socket;
public BufferedReader in;
public PrintWriter out;

public String error;

//Make a method that gets the username from the username field
public String username = "username"; 

public void changeStatusNTS(int newConnectStatus, boolean noError) {
    if(newConnectStatus != NULL) {
        connectionStatus = newConnectStatus;
    }

    if(noError) {
        statusString = statusMessages[connectionStatus];

    } else {
        statusString = statusMessages[NULL];

    }

    SwingUtilities.invokeLater(cs);
}

public void changeStatusTS(int newConnectStatus, boolean noError) {
    if(newConnectStatus != NULL) {
        connectionStatus = newConnectStatus;
    }

    if(noError) {
        statusString = statusMessages[connectionStatus];

    } else {
        statusString = statusMessages[NULL];

    }

    cs.run();
}

public void cleanUp() {

}

private void appendToChatBox(String s) {
    synchronized(toAppend) {
        toAppend.append(s);
    }
}

private void sendString(String s) {

}

@Override
public void run() {
    while(true) {
        try {
            Thread.sleep(10);

        } catch(InterruptedException e) {
            error = e.toString();
            //Append the error to the textArea
        }

        switch(connectionStatus) {
        case BEGIN_CONNECT:
            try {
                socket = new Socket(hostIP, port);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //I AM RIGHT HERE
                out = new PrintWriter(socket.getOutputStream(), true);
                changeStatusTS(CONNECTED, true);

            } catch(Exception e) {
                cleanUp();
                changeStatusTS(DISCONNECTED, false);

                error = e.toString();

            }

            break;

        case CONNECTED: 
            try {
                if(toSend.length() != 0) {
                    out.print(toSend);
                    out.flush();
                    toSend.setLength(0);
                    changeStatusTS(NULL, true);
                }

                if(in.ready()) {
                    String input = in.readLine();
                    if((input != null) && (input.length() != 0)) {
                        if(input.equals(END_CHAT_SESSION)) {
                            changeStatusTS(DISCONNECTING, true);

                        } else {
                            appendToChatBox(username + ": " + input + "\n");
                        }
                    }
                }
            }  catch(IOException e) {
                cleanUp();
                changeStatusTS(DISCONNECTED, false);

                error = e.toString();
            }
            break;

        case DISCONNECTING:
            out.print(END_CHAT_SESSION);
            out.flush();

            cleanUp();
            changeStatusTS(DISCONNECTED, true);

            break;

        default: break; //do nothing
        }
    }
}

class ActionAdapter implements ActionListener {
    public void actionPerformed(ActionEvent e) {}
}

}

N1ghtk1n9
  • 89
  • 3
  • 12

1 Answers1

0

You're getting a StackOverflow because of this

public class SocketManager extends JFrame implements Runnable {
    public ClientSwing cs = new ClientSwing();
....

public class ClientSwing extends JFrame implements Runnable {
    public SocketManager socketmanager = new SocketManager();

You're creating a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates a ClientSwing, which create a SocketManager, which creates aClientSwing, which create a SocketManager, which creates a.... StackOverflow

Get the picture??

  • If you want to need access to another class, don't instantiate it. You can pass one class to the other as a reference. And have appropriate getters and setters for the fields you want access to.
  • Or, you can create an MVC design, which is a more appropriate way to sharing data between classes.

Side Note


EDIT

Something like this would be the for pointed posibility. Instead of instantiating, pass by value

public class ClientSwing ...{
    SocketManager socketManager;
    public ClientManger(SocketManager socketManger) {
        this.socketManage = socketManager;
    }
}
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks so much for the quick response! I am not trying to be rude, I am really grateful for the help, but how am I using multiple JFrames/how does it apply to this situtation? I am reading the post anyways, of course. Also, what is a way around my problem? I was thinking to put the variables I have to call from one of the classes as static so I don't have to instantiate(correct use of the word?) the SocketManager class, and I can just do `SocketManager.connectionStatus`. Would this work? Again, thanks so much for the help – N1ghtk1n9 Jan 31 '14 at 16:39
  • Look at my **UPDATE**. Also, you are using multiple `JFrame`s, but it isn't the problem. As you can see, it was just a **Side Note**. Just a friendly suggestion. – Paul Samsotha Jan 31 '14 at 16:48
  • When you mean JFrames, you're not talking about JPanels right? – N1ghtk1n9 Feb 03 '14 at 15:40
  • I was actually referring to `ClientMain`, `ClientSwing` and `SocketManager` – Paul Samsotha Feb 03 '14 at 15:42
  • OH, I see what you mean. The only reason I have those extending JFrame is so I can use `SwingUtilities.invokeLater()` in my SocketManager class. Is there a better way of doing this? – N1ghtk1n9 Feb 03 '14 at 15:45
  • If you can explain the flow of these three classes (how they flow with the program) maybe I can offer some suggestions. – Paul Samsotha Feb 03 '14 at 15:50
  • I don't know what you mean by that, can you clarify for me? – N1ghtk1n9 Feb 03 '14 at 15:55
  • Like how exactly does the program flow. Like when does one frame open when does the other? What causes which frame to open. And why do you need the reference of the classes inside each other. I can't really offer suggestions if I don't know these things. I might give you some wrong advice. – Paul Samsotha Feb 03 '14 at 15:56
  • I think that you think that the `SocketManager`, `ClientMain`, and `ClientSwing` are all separate JFrames. The only real frame there is is the frame from ClientSwing, which is the class that controls all of the GUI of the client/messenger. The SocketManager, as it sounds, controls more of the network part of the program. I will explain more if needed, but I think I got it. What I meant by "Is there a better way of doing this, is that in SocketManagers method, `changeStatusNTS`, which is a a method that changes the status of the program(or the `connectionStatus` variable in the program) – N1ghtk1n9 Feb 04 '14 at 15:43
  • More explanation on the reason I have SocketManager extending JFrame: I do this so I can run the `SwingUtilities.invokeLater(ClientSwing)`. I need to run that so the ClientSwing class gets updated and all of the GUI parts(not yet implemented) will be disabled. For example, if the status of the messenger is connected, then it'd disable the JTextField for the port. Since you're currently using the port in that textfield, there is no reason of changing it. – N1ghtk1n9 Feb 04 '14 at 15:47