Frozen Swing GUI

Why is my Gui freezing?

Page 1 of 1

6 Replies - 7174 Views - Last Post: 01 January 2012 - 04:18 PM Rate Topic: -----

#1 mdhol  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 03-November 09

Frozen Swing GUI

Post icon  Posted 04 November 2009 - 09:16 AM

Hi,

I am writing a simple file server program with a swing gui. You get to enter a port and a directory to serve files from then hit the start button. It should send output such as errors, if any, your port #, directory, etc. to the displayArea textArea of the gui. However, once the staert button is hit, the gui locks up. I know the program is still running though because if I send all the output that I want to go to my gui to the console, that displays fine. The GUI just remains locked up though,

Here is my code:
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.event.*;
   
public class FileServer extends JFrame  {
	private int listeningPort;
	private File directory;
	private ServerSocket listener;
	private Socket connection;
	
	private JPanel displayPanel = new JPanel(new BorderLayout());
	private JPanel fieldsPanel = new JPanel();
	private JPanel panel = new JPanel(new BorderLayout());
	private JTextArea displayArea = new JTextArea();
	private JTextField portField = new JTextField(6);
	private JTextField directoryField = new JTextField(12);
	private JButton startButton = new JButton("Start Server");
	
	public FileServer()
	{
		fieldsPanel.add(new JLabel("Port: "));
		fieldsPanel.add(portField);
		fieldsPanel.add(new JLabel("Directory: "));
		fieldsPanel.add(directoryField);
		
		panel.add(fieldsPanel, BorderLayout.CENTER);
		panel.add(startButton, BorderLayout.SOUTH);
		
		displayPanel.add(panel, BorderLayout.SOUTH);
		displayPanel.add(displayArea, BorderLayout.CENTER);
		
		add(displayPanel);
		
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String portString = portField.getText();
				String directoryString = directoryField.getText();
				
				int portNumber = Integer.parseInt(portString);
				if(portNumber > 1021 && portNumber <= 65536)
				{
					listeningPort = portNumber;
					displayArea.setText("Port Number: " + portNumber + 
					"\nServer Directory: " + directoryString);
					
				}
				else 
				{
					displayArea.setText("Please enter a valid port " +
					"along with a server directory.");
				}
				
				directory = new File(directoryString);
				if(!directory.exists() || !directory.isDirectory())
				{
					displayArea.setText("Invalid Directory");
				}
				
				// Listen for connection requests and spawn handlers
				spawnConnection();
				
			}
		});
		
		
		
		
	}
	
	private void spawnConnection()
	{
		try
		{
			listener = new ServerSocket(listeningPort);
			displayArea.setText("\n\nListening on port: " + portField.getText());
			System.out.println("listening");
			
			while(true)
			{
				connection = listener.accept();
				new ConnectionHandler(directory, connection);
			}
		}
		catch(Exception ex)
		{
			displayArea.setText("\nServer shut down unexpectedly.");
			System.out.println("unexpected shutdown");
		}
	}
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
		   public void run() {
			 FileServer server = new FileServer();
			 server.setSize(500,800);
			 server.setLocationRelativeTo(null);
			 server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			 server.setTitle("Exercise29_1");
			 server.setVisible(true);
		}
		});
	  }
	
}



Here is the Connection Handler class:
import java.net.*;
import java.io.*;

public class ConnectionHandler extends Thread {
	File directory;
	Socket connection;
	TextReader incoming;
	PrintWriter outgoing;
	
	ConnectionHandler(File dir, Socket conn) 
	{
		directory = dir;
		connection = conn;
		start();
	}
	
	void sendIndex() throws Exception 
	{
		// called by run in response to index command
		// sends list of files in directory
		String[] fileList = directory.list();
		for(int i = 0; i < fileList.length; i++)
			outgoing.println(fileList[i]);
			
		outgoing.flush();
		outgoing.close();
		
		if(outgoing.checkError())
			throw new Exception("Transmission Error.");
	}
	
	void sendFile(String fileName) throws Exception
	{
		// called by run in response to get<fileName>
		File file = new File(directory, fileName);
		
		if((!file.exists()) || file.isDirectory())
		{
			outgoing.println("Error!");
		}
		else
		{
			outgoing.println("OK");
			TextReader fileIn = new TextReader(new FileReader(file));
			while(fileIn.peek() != 'Z') // this is a likely culprit.  Is this the proper control char for end of file????
			{
				String line = fileIn.getln();
				outgoing.println(line);
			}
			outgoing.flush();
			outgoing.close();
			
			if(outgoing.checkError())
				throw new Exception("Transmission Error!");
		}
	}
	
	public void run()
	{
		// executed by the thread
		// creates communication streams, reads, executes cmd
		String command = "Command not read";
		
		try
		{
			incoming = new TextReader(connection.getInputStream());
			outgoing = new PrintWriter(connection.getOutputStream());
			command = incoming.getln();
			
			if(command.equals("index"))
			{
				sendIndex();
			}
			else if(command.startsWith("get"))
			{
				String fileName = command.substring(3).trim();
				sendFile(fileName);
			}
			else
			{
				outgoing.println("Unknown Command!");
				outgoing.flush();
			}
			System.out.println("OK	" + connection.getInetAddress() +
				" " + command + " " + command);
		}
		catch(Exception e)
		{
			System.out.println("ERROR " + connection.getInetAddress() +
				" " + command + " " + e);
		}
		finally
		{
			try
			{
				connection.close();
			}
			catch(IOException e)
			{
				
			}
		}
	}
}



I think what I have is a threading issue but its got me stumped. Help!

Thanks in advance...

BTW: I posted this here because as this question deals specifically with swing and thread safety, it wouldn't have made sense to add it to my other thread, which deals with a totally different issue.

Is This A Good Question/Topic? 0
  • +

Replies To: Frozen Swing GUI

#2 mdhol  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 03-November 09

Re: Frozen Swing GUI

Posted 04 November 2009 - 10:01 AM

I have improved my code somewhat but the problem remains unsolved.

I know this is more complex - at least lengtier - than the typical questions that get answers on this forum but I hope someone will help me out.

Here is the latest version: < changes were only made to FileServer, the rest of the code remains the same >

import java.net.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.event.*;
   
public class FileServer extends JFrame   {
	private int listeningPort;
	private File directory;
	private ServerSocket listener;
	private Socket connection;
	
	private JPanel displayPanel = new JPanel(new BorderLayout());
	private JPanel fieldsPanel = new JPanel();
	private JPanel panel = new JPanel(new BorderLayout());
	private JTextArea displayArea = new JTextArea();
	private JTextField portField = new JTextField(6);
	private JTextField directoryField = new JTextField(12);
	private JButton startButton = new JButton("Start Server");
	
	
	public FileServer()
	{
		fieldsPanel.add(new JLabel("Port: "));
		fieldsPanel.add(portField);
		fieldsPanel.add(new JLabel("Directory: "));
		fieldsPanel.add(directoryField);
		
		panel.add(fieldsPanel, BorderLayout.CENTER);
		panel.add(startButton, BorderLayout.SOUTH);
		
		displayPanel.add(panel, BorderLayout.SOUTH);
		displayPanel.add(displayArea, BorderLayout.CENTER);
		
		add(displayPanel);
		
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String portString = portField.getText();
				String directoryString = directoryField.getText();
				
				int portNumber = Integer.parseInt(portString);
				
				if(portNumber > 1021 && portNumber <= 65536)
				{
					listeningPort = portNumber;
					
					displayArea.setText("Port Number: " + portNumber +
					" " + "\nServer Directory: " + directoryString);
					
					directory = new File(directoryString);
					if(directory.exists() && directory.isDirectory())
					{
						display("Listening");
						spawnConnection();
						
					}
					else
					{
						displayArea.setText("\n\nPlease enter valid data.");
					}
					
				}
			}
		});
			
	
	}
	
	private void display(String listening)
	{
		displayArea.setText("Listening");
	}
	
	private void spawnConnection()
	{
		try
		{
			listener = new ServerSocket(listeningPort);
			displayArea.setText("\n\nListening on port: " + portField.getText());
			System.out.println("listening");
			
			while(true)
			{
				connection = listener.accept();
				new ConnectionHandler(directory, connection);
			}
		}
		catch(Exception ex)
		{
			displayArea.setText("\nServer shut down unexpectedly.");
			System.out.println("unexpected shutdown");
		}
	}
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
		   public void run() {
			 FileServer server = new FileServer();
			 server.setSize(500,800);
			 server.setLocationRelativeTo(null);
			 server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			 server.setTitle("Exercise29_1");
			 server.setVisible(true);
		}
		});
	  }
	
}




Is the issue that I am opening that socket and listening on the same thread as my GUI? The gui displays errors but will not display the "listening" status message adn the button remains frozen.

I thought "invokeLater" from SwingUtilities would take care fo that for me? Guess not.

Help!
Was This Post Helpful? 0
  • +
  • -

#3 TriggaMike  Icon User is offline

  • Using up all your 1's and 0's
  • member icon

Reputation: 85
  • View blog
  • Posts: 1,103
  • Joined: 26-September 08

Re: Frozen Swing GUI

Posted 04 November 2009 - 10:17 AM

You need to have this code inside it's own thread with other necessary parameters to support it, but this code is why you're freezing:

while(true)
            {
                connection = listener.accept();
                new ConnectionHandler(directory, connection);
            }


You shouldn't have infinite listener loops outside of threads, will cause all sorts of hell for your program.
Was This Post Helpful? 0
  • +
  • -

#4 mdhol  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 03-November 09

Re: Frozen Swing GUI

Posted 04 November 2009 - 10:21 AM

View PostTriggaMike, on 4 Nov, 2009 - 09:17 AM, said:

You need to have this code inside it's own thread with other necessary parameters to support it, but this code is why you're freezing:

while(true)
            {
                connection = listener.accept();
                new ConnectionHandler(directory, connection);
            }


You shouldn't have infinite listener loops outside of threads, will cause all sorts of hell for your program.



Funny, that had just occurred to me right before I checked and saw your answer so I am glad to see my suspicions confirmed.

Can you help me out a bit with getting this into it's own thread? Can I simply create a class that is its own thread and instantiate it exactly at this point in the program or does this new thread need to communicate with others?

I'm really weak on threads so if you can give me a few hints to get started, I'd rally appreciate it.

Thanks!
Was This Post Helpful? 0
  • +
  • -

#5 TriggaMike  Icon User is offline

  • Using up all your 1's and 0's
  • member icon

Reputation: 85
  • View blog
  • Posts: 1,103
  • Joined: 26-September 08

Re: Frozen Swing GUI

Posted 04 November 2009 - 11:19 AM

I can point you in the right direction but I don't exactly have time to provide more specific example code right now.

You need to know how to use:

Streams
Observers/Observables
Runnable/Thread

You will need a listener class that extends Observable and implements runnable. You will need to make your GUI implement observer and write an update method inside your GUI to accept interactions through the stream that should be used to facilitate communication between the observer and the observable.
Was This Post Helpful? 0
  • +
  • -

#6 mdhol  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 03-November 09

Re: Frozen Swing GUI

Posted 04 November 2009 - 12:27 PM

View PostTriggaMike, on 4 Nov, 2009 - 10:19 AM, said:

I can point you in the right direction but I don't exactly have time to provide more specific example code right now.

You need to know how to use:

Streams
Observers/Observables
Runnable/Thread

You will need a listener class that extends Observable and implements runnable. You will need to make your GUI implement observer and write an update method inside your GUI to accept interactions through the stream that should be used to facilitate communication between the observer and the observable.



Thanks, that ought to get me moving in the right direction. If anyone else is watching this thread, here is my latest attempt, which is somewhat of a move in the direction you were speaking of, but lacking much of it.

I nixed that whole try catch block with the while loop inside spawnConnection and instead instantiated a ConnectionSpawner object and passed it as parameters all of the variables and objects that were working inside it.

Here's the code - which of course doesn't work, but if you have time later or someone else is interested in helping me out, I'd appreciate if you could help me fix or nudge me further in the right direction. Meantime, I'm researching Observers and Observables, which I've not encountered before.

import java.io.*;
import java.net.*;
import javax.swing.*;

public class ConnectionSpawner implements Runnable {
	ServerSocket listener;
	Socket connection;
	File directory;
	JTextArea displayArea;
	JTextArea portField;
	int listeningPort;
	
	public ConnectionSpawner(ServerSocket listener, Socket connection, File directory, JTextArea displayArea, JTextArea portField, int listeningPort)
	{
		this.listener = listener;
		this.connection = connection;
		this.directory = directory;
		this.displayArea = displayArea;
		this.portField = portField;
		this.listeningPort = listeningPort;
	}
	public void run()
	{	
		try // start a worker thread for this .  its the infinite whileloop. 
		{
			listener = new ServerSocket(listeningPort);
			displayArea.setText("\n\nListening on port: " + portField.getText());
			System.out.println("listening");
			while(true) 
			{
				connection = listener.accept();
				new ConnectionHandler(directory, connection);
			}
		}
		catch(Exception e) 
					
		{
			displayArea.setText("\nServer shut down unexpectedly.");
			System.out.println("unexpected shutdown");
		}

	}
	
}



Thanks again!
Was This Post Helpful? 0
  • +
  • -

#7 Ghlavac  Icon User is offline

  • D.I.C Addict

Reputation: 84
  • View blog
  • Posts: 519
  • Joined: 14-January 09

Re: Frozen Swing GUI

Posted 01 January 2012 - 04:18 PM

If you want that connectionhandler to work, you have to start it in a new thread, it won't automatically, so it would have to also implement runnable like connectionspawner.

Like this..

new Thread(new ConnectionHandler(directory, connection)).start();


This post has been edited by Ghlavac: 01 January 2012 - 04:19 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1