I have a method showMessage() that appends a string onto a JTextArea and i want to call it in my "class in the class" (ServerThread). How can i accomplish this without having Main main; or Main main = new Main();
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
}
}
Example: in the run method i want to have something like main.showMessage(string) without having a Main object declared.
Just declare your method as static
public static void showMessage(final String m)
That way, you can call it like this -
Main.showMessage("Some String");
declare both showMessage method and chatWindow field static. Then you can call as Main.showMessage("whatever") where you want.
But a more elegant solution will be communicating these two singletons over listeners.
Declare an interface MessageListener with a method say onMessage(String message)
interface MessageListener {
public void onMessage(String message);
}
in ServerThread keep a list of MessageListeners and in run method invoke them
class ServerThread extends Thread {
// class content
static List<MessageListener> messageListeners = new ArrayList<>();
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
then make your Main class implementing MessageListener and in onMessage method call showMessage, also do not forget to register ServerThreads listener registry
public class Main extends JFrame implements MessageListener {
// class content
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
// other content
}
// class content
#Override
public void onMessage(String message) {
showMessage(message);
}
}
that's all. then the whole code looks like:
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class Main extends JFrame implements MessageListener {
private static final long serialVersionUID = 1L;
private JTextArea chatWindow;
private List<Integer> ports = new ArrayList<Integer>();
public Main() throws IOException {
super("ServerConsole");
ServerThread.messageListeners.add(this);
chatWindow = new JTextArea();
chatWindow.setEditable(false);
JScrollPane scrollPane = new JScrollPane(chatWindow);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(0, 20, 596, 200);
add(scrollPane);
setLayout(null);
setSize(600, 300);
setResizable(false);
setVisible(true);
getContentPane().setBackground(Color.white);
Socket s = null;
ServerSocket ss2 = null;
showMessage("Server Listening......\n");
try {
ss2 = new ServerSocket(3175);
} catch (IOException e) {
e.printStackTrace();
showMessage("Server error");
}
while (true) {
try {
s = ss2.accept();
showMessage("connection Established\n");
ports.add(s.getPort());
ServerThread st = new ServerThread(s);
st.start();
}
catch (Exception e) {
e.printStackTrace();
showMessage("Connection Error");
}
}
}
public void showMessage(final String m) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatWindow.append(m);
}
});
}
#Override
public void onMessage(String message) {
showMessage(message);
}
}
interface MessageListener {
public void onMessage(String message);
}
class ServerThread extends Thread {
private ObjectOutputStream output;
private ObjectInputStream input;
Socket s = null;
private static LinkedHashMap<Integer, String> playerCoords = new LinkedHashMap<Integer, String>();
static List<MessageListener> messageListeners = new ArrayList<>();
public ServerThread(Socket s) {
this.s = s;
}
public void run() {
for (MessageListener messageListener : messageListeners) {
messageListener.onMessage("the message");
}
}
}
Related
I am developing a messaging application with sockets. I have an initial JFrame that allows the user to choose a contact to connect to, and lets them choose if they'd like to be the client or the server. When they make this choice, it calls a method in which creates the chat window frame, and also uses a SwingWorker to initialise a connection, create an action listner on the send buton of the chat window so that it sends messages when pressed, and creates a SocketListener that is always listening while the window is open.
This works just fine, however if I close the chat window and then reopen it by choosing server or client again, nothing happens - the frame loads up however I cannot send any messages on it.
I'm not sure what the problem is here, could it be that i'm not disposing of the swing worker or the frame properly? Any help would be greatly appreciated and apologies for my lack of knowledge.
Here is the relevent code for this:
public static void server() {
JButton server = new JButton();
server.setText("Server");
server.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String name = nameChoice;
String ip = ipChoice;
String port = portChoice;
try {
server2(port);
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
panel.add(server);
}
public static void server2(String port) throws Exception {
gui.frame();
SwingWorker worker = new SwingWorker() {
#Override
protected Void doInBackground() throws Exception {
sockets.serverSetup(port);
gui.sendButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String msg = gui.newMsg.getText();
gui.newMsg.setText(null);
try {
sockets.sendMsg(msg);
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
while(gui.open==true) {
sockets.receiveMsg();
}
sockets.closeConnection();
System.out.println("Closed");
return null;
}
};
worker.execute();
}
network
package com.company;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Vector;
public class network {
static ServerSocket s;
static Socket s1;
static OutputStream s1out;
static DataOutputStream dos;
static InputStream s1in;
static chatWindowScreen gui = new chatWindowScreen();
static String st;
public static Vector sentVec = new Vector();
public static Vector receivedVec = new Vector();
public static Vector messages = new Vector();
public static void serverSetup(String port) throws IOException {
System.out.println("Test");
int portInt = Integer.parseInt(port);
s = new ServerSocket(portInt);
s1 = s.accept();
System.out.println("Server set up");
//sendMsg("Hi");
}
public static void clientSetup(String port, String ip) throws IOException {
System.out.println("Test");
int portInt = Integer.parseInt(port);
s1 = new Socket(ip, portInt);
System.out.println("Client set up");
//receiveMsg();
}
public static void closeConnection() throws IOException {
dos.close();
s1out.close();
s1.close();
}
public static void sendMsg(String message) throws IOException {
System.out.println("Test");
s1out = s1.getOutputStream();
dos = new DataOutputStream(s1out);
dos.writeUTF(message);
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String t1 = sdf.format(cal.getTime());
message = t1 + " - " + message;
sentVec.add(message);
receivedVec.add("");
messages.add(message);
gui.sent.setText("Sent \n");
for (int i = 0; i < sentVec.size(); i++) {
gui.sent.append(sentVec.get(i) + "\n");
}
gui.received.setText("Received \n");
for (int i = 0; i < receivedVec.size(); i++) {
gui.received.append(receivedVec.get(i) + "\n");
}
System.out.println("complete");
}
public static void receiveMsg() throws IOException {
System.out.println("Test");
s1in = s1.getInputStream();
DataInputStream dis = new DataInputStream(s1in);
st = (dis.readUTF());
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String t1 = sdf.format(cal.getTime());
st = t1 + " - " + st;
receivedVec.add(st);
sentVec.add("");
messages.add(st);
gui.received.setText("Received \n");
for (int i = 0; i < receivedVec.size(); i++) {
gui.received.append((String) receivedVec.get(i) + "\n");
}
gui.sent.setText("Sent \n");
for (int i = 0; i < sentVec.size(); i++) {
gui.sent.append((String) sentVec.get(i) + "\n");
}
}
public static Vector getSentVec() {
return sentVec;
}
public static Vector getReceivedVec() {
return receivedVec;
}
}
chatWindowScreen
package com.company;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.util.Vector;
public class chatWindowScreen {
static JFrame frame = new JFrame();
static JPanel panel = new JPanel();
static JTextArea sent;
static JTextArea received;
static JTextArea newMsg;
static JButton sendButton;
public static String msg;
static boolean open = true;
static network sockets = new network();
public static boolean close = false;
public void frame() throws Exception {
System.out.println("GUI opened");
frame.setTitle("Messaging Application");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowListener() {
#Override
public void windowOpened(WindowEvent e) {
}
#Override
public void windowClosing(WindowEvent e) {
}
#Override
public void windowClosed(WindowEvent e) {
System.out.println("Closed");
panel.removeAll();
open=false;
}
#Override
public void windowIconified(WindowEvent e) {
}
#Override
public void windowDeiconified(WindowEvent e) {
}
#Override
public void windowActivated(WindowEvent e) {
}
#Override
public void windowDeactivated(WindowEvent e) {
}
});
sentMsg();
receivedMsg();
msgBox();
sendBtn();
save();
frame.add(panel);
frame.setVisible(true);
}
public static void sentMsg() {
sent = new JTextArea(15, 20);
sent.setText("Sent" + "\n");
sent.setLineWrap(true);
sent.setEditable(false);
JScrollPane pane = new JScrollPane(sent, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
panel.add(pane);
}
public static void receivedMsg() {
received = new JTextArea(15, 20);
received.setText("Received" + "\n");
received.setEditable(false);
received.setLineWrap(true);
JScrollPane pane1 = new JScrollPane(received, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
panel.add(pane1);
}
public static void msgBox() {
newMsg = new JTextArea(1, 15);
newMsg.setText("");
newMsg.setLineWrap(true);
JScrollPane pane2 = new JScrollPane(newMsg, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
panel.add(pane2);
}
public static void sendBtn() {
sendButton = new JButton();
sendButton.setText("Send!");
/*sendButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
msg = newMsg.getText();
newMsg.setText(null);
SwingWorker worker = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
sockets.sendMsg(msg);
return null;
}
};
worker.execute();
try {
sockets.sendMsg(msg);
} catch (IOException e1) {
e1.printStackTrace();
}
msg = null;
}
});*/
panel.add(sendButton);
}
public static void save(){
JButton save = new JButton();
save.setText("Save Conversation");
save.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
saveToFile save = new saveToFile();
}
});
panel.add(save);
}
}
Basically I am just writing a socket.
For some reason I keep getting this error though
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Main.ChatClient.main(ChatClient.java:143)
which is line " String server = args[0]; "
What does the args need to be to fix this issue?
package Main;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Observable;
import java.util.Observer;
// Class to manage Client chat Box.
public class ChatClient {
Main a = new Main();
/** Chat client access */
static class ChatAccess extends Observable {
private Socket socket;
private OutputStream outputStream;
#Override
public void notifyObservers(Object arg) {
super.setChanged();
super.notifyObservers(arg);
}
/** Create socket, and receiving thread */
public void InitSocket(String server, int port) throws IOException {
socket = new Socket(server, port);
outputStream = socket.getOutputStream();
Thread receivingThread = new Thread() {
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
notifyObservers(line);
} catch (IOException ex) {
notifyObservers(ex);
}
}
};
receivingThread.start();
}
private static final String CRLF = "\r\n"; // newline
/** Send a line of text */
public void send(String text) {
try {
outputStream.write((text + CRLF).getBytes());
outputStream.flush();
} catch (IOException ex) {
notifyObservers(ex);
}
}
/** Close the socket */
public void close() {
try {
socket.close();
} catch (IOException ex) {
notifyObservers(ex);
}
}
}
/** Chat client UI */
static class ChatFrame extends JFrame implements Observer {
private JTextArea textArea;
private JTextField inputTextField;
private JButton sendButton;
private ChatAccess chatAccess;
public ChatFrame(ChatAccess chatAccess) {
this.chatAccess = chatAccess;
chatAccess.addObserver(this);
buildGUI();
}
/** Builds the user interface */
private void buildGUI() {
textArea = new JTextArea(20, 50);
textArea.setEditable(false);
textArea.setLineWrap(true);
add(new JScrollPane(textArea), BorderLayout.CENTER);
Box box = Box.createHorizontalBox();
add(box, BorderLayout.SOUTH);
inputTextField = new JTextField();
sendButton = new JButton("Send");
box.add(inputTextField);
box.add(sendButton);
// Action for the inputTextField and the goButton
ActionListener sendListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String str = inputTextField.getText();
if (str != null && str.trim().length() > 0)
chatAccess.send(str);
inputTextField.selectAll();
inputTextField.requestFocus();
inputTextField.setText("");
}
};
inputTextField.addActionListener(sendListener);
sendButton.addActionListener(sendListener);
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
chatAccess.close();
}
});
}
/** Updates the UI depending on the Object argument */
public void update(Observable o, Object arg) {
final Object finalArg = arg;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(finalArg.toString());
textArea.append("\n");
}
});
}
}
public static void main(String[] args) {
System.out.println("troll");
String server = args[0];
System.out.println("reached here");
int port =2222;
ChatAccess access = new ChatAccess();
JFrame frame = new ChatFrame(access);
frame.setTitle("MyChatApp - connected to " + server + ":" + port);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
try {
access.InitSocket(server,port);
} catch (IOException ex) {
System.out.println("Cannot connect to " + server + ":" + port);
ex.printStackTrace();
System.exit(0);
}
}
}
Given:
String server = args[0];
I'd suggest you provide the server name as your first argument to your program
With
public static void main(String[] args)
args is the array of command line args passed in.
I am trying to build a Swing solution for compressing files which is relayed on the rar command line. As the GUI needs to stay responsive I've wrapped the code for dealing with the command line into a SwingWorker class.
SwingWorker<Boolean, String> worker = new SwingWorker<Boolean, String>(){
protected Boolean doInBackground() throws Exception {
Runtime rt = Runtime.getRuntime();
try {
//daj processu da ode u background nekako, da ga ne sjebem sa ctrl + c (winrar umesto rar)
String command = "my command, this works just fine";
Process p = rt.exec(command, null, new File("C:\\Program Files\\WinRar"));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String s = null;
System.out.println("<INPUT>");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("</INPUT>");
InputStream stderr = p.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
System.out.println("<ERROR>");
String line = null;
while ( (line = br.readLine()) != null){
System.out.println(line);
return false;
}
System.out.println("</ERROR>");
int exitVal = p.waitFor();
//EXIT VALUE IS ALWAYS 0, EVEN IF I INTERRUPT IT WITH CTRL+C
System.out.println("Process exitValue: " + exitVal);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
return false;
}
return true;
}
#Override
protected void process(List<String> chunks) {
// TODO Auto-generated method stub
//SOME GUI UPDATES
}
#Override
protected void done() {
// TODO Auto-generated method stub
Boolean status = false;
try {
status = get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//MORE GUI UPDATES
if(status){
tableList.setValueAt("Done", row, 3);
} else{
tableList.setValueAt("Error", row, 3);
}
super.done();
}
};
worker.execute();
When I delete printing of input and error, exit value is printed as soon as rar appears on the screen. So there is no actual point of "waitFor()" method in my code. What I need is to check if rar closed without interrupts (like CTRL + C, or hitting "X" on cmd window) and get the exit code. I've tried adding shutdown hook on runtime (rt variable) but it reacts when I close the whole GUI.
You need to get your input and error streams, and read from them each in its own thread. Right now your error stream never has a chance because of the blocking while loop ahead of it.
I've used the following code (although it is years old...):
Enum: GobblerType.java
enum GobblerType {
ERROR, OUTPUT
}
Class StreamGobbler.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
public class StreamGobbler implements Runnable {
private InputStream is;
private GobblerType type;
private OutputStream os;
public StreamGobbler(InputStream is, GobblerType type) {
this(is, type, null);
}
public StreamGobbler(InputStream is, GobblerType type, OutputStream redirect) {
this.is = is;
this.type = type;
this.os = redirect;
}
public void run() {
try {
PrintWriter pw = null;
if (os != null) {
pw = new PrintWriter(os, true);
}
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (pw != null) {
pw.println(line);
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
And then have used it like so:
Process proc = Runtime.getRuntime().exec(.....); // TODO: Fix!
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), GobblerType.ERROR);
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), GobblerType.OUTPUT);
new Thread(errorGobbler).start();
new Thread(outputGobbler).start();
int exitVal = proc.waitFor();
proc.destroy();
OK, I created some code as a proof of concept program. I've modified my Gobbler a bit so that it doesn't require an OutputStream but rather uses a PropertyChangeListener to notify listeners of any text coming from the InputStream. For this to work, all my code is in the same package, and note that package names are key, and you would likely need to change yours. Running this code does behave as expected. It is a bit overly simplistic and probably should use some type of blocking queue for passing information between classes.
GobblerType.java
An enum to distinguish the two type of stream gobblers in use
package pkg2;
public enum GobblerType {
ERROR, OUTPUT
}
StreamGobbler2.java
The stream gobbler that uses an input stream reader to get text from the input stream, puts the text into a text field, and notifies listeners of new text. It uses a PropertyChangeListener for the notification. This is a crude way to producer-consumer, and risks not capturing all passed information. Better would be to use a blocking queue of some sort.
package pkg2;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
public class StreamGobbler2 implements Callable<Void> {
private PropertyChangeSupport support = new PropertyChangeSupport(this);
private InputStream is;
private GobblerType type;
private String text;
public StreamGobbler2(InputStream is, GobblerType type) {
this.is = is;
this.type = type;
}
#Override
public Void call() throws Exception {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
setText(line);
}
return null;
}
public GobblerType getType() {
return type;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
public void setText(String text) {
String oldValue = null;
String newValue = text;
this.text = text;
support.firePropertyChange(type.toString(), oldValue, newValue);
}
public String getText() {
return text;
}
}
ProcessLauncher.java
This is a non-Swing class that captures the information from the two gobblers. Again, better would be to use blocking queues (next iteration)
package pkg2;
import java.beans.PropertyChangeListener;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ProcessLauncher implements Callable<Integer> {
private ExecutorService execService = Executors.newFixedThreadPool(2);
private List<String> commands;
private List<PropertyChangeListener> listeners = new ArrayList<>();
public ProcessLauncher(List<String> commands) {
this.commands = commands;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.add(listener);
}
#Override
public Integer call() throws Exception {
ProcessBuilder pb = new ProcessBuilder(commands);
Process p = pb.start();
int exitValue = 0;
try (InputStream inputStream = p.getInputStream();
InputStream errorStream = p.getErrorStream()) {
StreamGobbler2 errorGobbler = new StreamGobbler2(inputStream, GobblerType.OUTPUT);
StreamGobbler2 outputGobbler = new StreamGobbler2(errorStream, GobblerType.ERROR);
for (PropertyChangeListener listener : listeners) {
errorGobbler.addPropertyChangeListener(listener);
outputGobbler.addPropertyChangeListener(listener);
}
List<Future<Void>> futures = new ArrayList<>();
futures.add(execService.submit(errorGobbler));
futures.add(execService.submit(outputGobbler));
execService.shutdown();
exitValue = p.waitFor();
for (Future<Void> future : futures) {
future.get();
}
}
return exitValue;
}
}
SwingWorkerWrapper.java
Wrapper to use the above class in a Swing fashion
package pkg2;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.SwingWorker;
public class SwingWorkerWrapper extends SwingWorker<Integer, Void> {
private ProcessLauncher processLauncher;
public SwingWorkerWrapper(List<String> commands) {
processLauncher = new ProcessLauncher(commands);
processLauncher.addPropertyChangeListener(new LauncherListener());
}
#Override
protected Integer doInBackground() throws Exception {
return processLauncher.call();
}
private class LauncherListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
}
}
MainGui.java
GUI class that uses the above SwingWorker. Run this class to get the whole show on the road. Once running, press the "Launch Process" button for this program to run the TestProgram in a separate JVM.
package pkg2;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class MainGui extends JPanel {
private static final String[] CMD_TEXT = {"java", "-cp"};
private static final String TEST_PROGRAM = "pkg2.TestProgram";
private JTextArea inputTextArea = new JTextArea(15, 30);
private JTextArea errorTextArea = new JTextArea(15, 30);
private List<String> commands = new ArrayList<>();
public MainGui() {
for (String cmd : CMD_TEXT) {
commands.add(cmd);
}
String classpath = System.getProperty("java.class.path");
commands.add(classpath);
commands.add(TEST_PROGRAM);
inputTextArea.setFocusable(false);
JScrollPane inputScrollPane = new JScrollPane(inputTextArea);
inputScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Border outsideBorder = BorderFactory.createTitledBorder("Input Messages");
Border border = BorderFactory.createCompoundBorder(outsideBorder, inputScrollPane.getBorder());
inputScrollPane.setBorder(border);
errorTextArea.setFocusable(false);
JScrollPane errorScrollPane = new JScrollPane(errorTextArea);
errorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
outsideBorder = BorderFactory.createTitledBorder("Error Messages");
border = BorderFactory.createCompoundBorder(outsideBorder, errorScrollPane.getBorder());
errorScrollPane.setBorder(border);
JPanel twoAreasPanel = new JPanel(new GridLayout(1, 0, 3, 3));
twoAreasPanel.add(inputScrollPane);
twoAreasPanel.add(errorScrollPane);
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 3, 3));
btnPanel.add(new JButton(new LaunchProcessAction()));
btnPanel.add(new JButton(new ExitAction()));
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
setLayout(new BorderLayout(3, 3));
add(twoAreasPanel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
private class SwWrapperListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
SwingWorkerWrapper swW = (SwingWorkerWrapper) evt.getSource();
try {
int exitCode = swW.get();
inputTextArea.append("Exit Code: " + exitCode + "\n");
} catch (InterruptedException e) {
e.printStackTrace();
inputTextArea.append(e.getLocalizedMessage());
inputTextArea.append("\n");
} catch (ExecutionException e) {
e.printStackTrace();
inputTextArea.append(e.getLocalizedMessage());
inputTextArea.append("\n");
}
} else if (GobblerType.OUTPUT.toString().equals(evt.getPropertyName())) {
inputTextArea.append(evt.getNewValue() + "\n");
} else if (GobblerType.ERROR.toString().equals(evt.getPropertyName())) {
errorTextArea.append(evt.getNewValue() + "\n");
}
}
}
private class LaunchProcessAction extends MyAction {
public LaunchProcessAction() {
super("Launch Process", KeyEvent.VK_L);
}
#Override
public void actionPerformed(ActionEvent e) {
SwingWorkerWrapper swWrapper = new SwingWorkerWrapper(commands);
swWrapper.addPropertyChangeListener(new SwWrapperListener());
swWrapper.execute();
}
}
private class ExitAction extends MyAction {
public ExitAction() {
super("Exit", KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private static abstract class MyAction extends AbstractAction {
public MyAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
}
private static void createAndShowGui() {
MainGui mainPanel = new MainGui();
JFrame frame = new JFrame("Main GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
TestProgram.java
Don't run this program directly, but rather have the Main GUI run this. Be sure that this code and all the code is compiled however
package pkg2;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestProgram extends JPanel {
private JTextField textField = new JTextField(20);
private JSpinner exitCodeSpinner = new JSpinner(new SpinnerNumberModel(0, -10, 10, 1));
public TestProgram() {
SendTextAction sendTextAxn = new SendTextAction();
textField.setAction(sendTextAxn);
JPanel panel1 = new JPanel();
panel1.add(textField);
panel1.add(new JButton(sendTextAxn));
JPanel panel2 = new JPanel();
panel2.add(new JLabel("Exit Code:"));
panel2.add(exitCodeSpinner);
panel2.add(new JButton(new ExitCodeAction()));
panel2.add(new JButton(new ThrowExceptionAction()));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(panel1);
add(panel2);
}
private static abstract class MyAction extends AbstractAction {
public MyAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
}
private class SendTextAction extends MyAction {
public SendTextAction() {
super("Send Text", KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
textField.setText("");
System.out.println(text);
}
}
private class ExitCodeAction extends MyAction {
public ExitCodeAction() {
super("Exit Code", KeyEvent.VK_X);
}
#Override
public void actionPerformed(ActionEvent e) {
int exitCode = (int) exitCodeSpinner.getValue();
System.exit(exitCode);
}
}
private class ThrowExceptionAction extends MyAction {
public ThrowExceptionAction() {
super("Throw Exception", KeyEvent.VK_T);
}
#Override
public void actionPerformed(ActionEvent e) {
// throw some unchecked exception
throw new NumberFormatException("Unchecked exception thrown from within TestProgram");
}
}
private static void createAndShowGui() {
TestProgram mainPanel = new TestProgram();
JFrame frame = new JFrame("Test Program");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I wrote this simple multi threaded chatroom, and I am trying to send the client/server output to GUI to display it in chatroom text area but I get null pointer exception at the following line:
output.write(line + "\n");
here is the full code for GUI:
import java.awt.*;
import javax.swing.*;
import javax.swing.JTextField;
import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import javax.swing.JButton;
import java.io.Writer;
public class GUI {
private JFrame frame;
private JButton btnSend, btnConnect;
private JTextArea txtChat;
private JTextField fldText, fldName;
private JList clientList;
private DefaultListModel listModel;
private JScrollPane sc, scClients;
private JPanel jpS2All, jpS2Client, jpS2Text;
private String Name;
private JLabel lblErr;
private Writer output;
public GUI(String Name, Writer output) {
this.Name = Name;
this.output = output;
}
public GUI() {
}
class handler implements ActionListener, MouseListener {
handler(String Name) {
}
handler() {
}
#Override
public void actionPerformed(ActionEvent e) {
clients(); //it seems this line made the error because it creates the
listModel.addElement(Name);//gui and sends the output to textSend actionlistener
//to display it in gui
//while the output is empty, right?
//is there any way to handle this?
}
#Override
public void mouseClicked(MouseEvent e) {
fldName.setText("");
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
} //end of handler
class textSend implements ActionListener {
textSend(String Name, Writer output) {
}
#Override
public void actionPerformed(ActionEvent e) {
String line = fldText.getText();
try {
output.write(line + "\n"); // the null exception error shows the
output.flush(); // error source at this line!
} catch (IOException ioe) {
txtChat.append("Other party hung up!");
}
String contenet = Name + ":" + output;
txtChat.append(contenet);
fldText.setText("");
}
}//end of textSend
public void creatServer() {
frame = new JFrame("enter");
frame.setBounds(50, 50, 300, 200);
btnConnect = new JButton("connect");
lblErr = new JLabel();
lblErr.setText("");
frame.add(btnConnect, BorderLayout.EAST);
fldName = new JTextField();
fldName.setText("enter your name");
fldName.addMouseListener(new handler());
btnConnect.addActionListener(new handler(getName()));
frame.add(fldName, BorderLayout.CENTER);
frame.setVisible(true);
}
public void clients() { //to create the chatroom GUI
frame = new JFrame("friends");
frame.setBounds(100, 100, 400, 400);
jpS2All = new JPanel();
txtChat = new JTextArea();
txtChat.setRows(25);
txtChat.setColumns(25);
txtChat.setEditable(false);
sc = new JScrollPane(txtChat);
jpS2All.add(sc);
frame.add(jpS2All, BorderLayout.WEST);
jpS2Text = new JPanel();
////////////////////////
fldText = new JTextField();
fldText.setColumns(34);
fldText.setHorizontalAlignment(JTextField.RIGHT);
fldText.addActionListener(new textSend(getName(), output));
jpS2Text.add(fldText);
frame.add(jpS2Text, BorderLayout.SOUTH);
/////////
jpS2Client = new JPanel();
listModel = new DefaultListModel();
clientList = new JList(listModel);
clientList.setFixedCellHeight(14);
clientList.setFixedCellWidth(100);
scClients = new JScrollPane(clientList);
frame.add(jpS2Client.add(scClients), BorderLayout.EAST);
/////////
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}//end of clients
public String getName() {
Name = fldName.getText();
return Name;
}
public void appendText(final String message) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
txtChat.append(message);
}
});
}
}
server code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class server {
public void start() throws IOException {
ServerSocket serverSocket = new ServerSocket(1234);
while (true) {
Socket socket = serverSocket.accept();
ClientThread t = new ClientThread(socket);
t.start();
}
}
public static void main(String[] args) throws IOException {
server server = new server();
server.start();
}
class ClientThread extends Thread {
Socket socket;
InputStream sInput;
OutputStream sOutput;
GUI gui = new GUI();
String Name;
ClientThread(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
BufferedReader sInput
= new BufferedReader(new InputStreamReader(socket.getInputStream()));
Writer sOutput = new OutputStreamWriter(socket.getOutputStream());
Name = gui.getName();
gui = new GUI(Name, sOutput);
try {
String line;
while ((line = sInput.readLine()) != null) {
gui.appendText(line);
}
} catch (IOException ex) {
Logger.getLogger(client.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (IOException e) {
}
}
}
}
client side:
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class client {
private Socket s;
private String Name;
private GUI gui;
private Writer output;
private BufferedReader input;
public void start() {
try {
s = new Socket("127.0.0.1", 1234);
} catch (IOException ex) {
}
try {
input = new BufferedReader(new InputStreamReader(s.getInputStream()));
output = new OutputStreamWriter(s.getOutputStream());
} catch (IOException eIO) {
}
Name = gui.getName();
new GUI(Name, output);
new ListenFromServer().start();
}
public static void main(String[] args) {
client cl = new client();
GUI gui = new GUI();
gui.creatServer();
}
class ListenFromServer extends Thread {
public void run() {
try {
String line;
while ((line = input.readLine()) != null) {
gui.appendText(line);
}
} catch (IOException ex) {
Logger.getLogger(client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
I know my question is a bit cumbersome but I really appreciate to help me handle this issue!
I am looking at your code and it is obvious that output is null when you attempt output.write(line + "\n"); Therefore I went and looked for the possible path of execution that could leave output un-initialized. This is where debugging comes in very handy.
Here is your execution path:
In your main method of client you create a new GUI and then call gui.creatServer();
public static void main(String[] args) {
client cl = new client();
GUI gui = new GUI();
gui.creatServer();
}
output has not been assigned and is still null
in the creatServer(); method you have this line:
fldName.addMouseListener(new handler());
which the actionPerformed method of handler calls the clients(); method which has the line:
fldText.addActionListener(new textSend(getName(), output));
note output is still null
(now your textSend class doesn't even do anything inside the constructor but that aside even if it did you are still using the output variable from the GUI class)
you have the actionPerformed method in the textSend class that has the line:
output.write(line + "\n");
Without ever initializing output it is still null, which gives you the NullPointer
Please see What is a NullPointerException, and how do I fix it? as #markspace linked in the comments. In addition you should really learn how to debug small programs.
See the following links:
http://ericlippert.com/2014/03/05/how-to-debug-small-programs/
http://blogs.msdn.com/b/smallbasic/archive/2012/10/09/how-to-debug-small-basic-programs.aspx
Again in addition, consider using Anonymous classes to ease up on those lines of code, which also makes the code easier to debug and more readable.
One last thought, remember to use standard Naming Conventions for the language you are using. your code currently has a lot of incorrect lowercase classes and some uppercase methods/properties.
the error message shows that one of the variable used in the expression was null. This may be either output or line.
As chancea already mentioned, you are calling the GUI() constructor with no arguments, so the output field is not initialized. You should remove the constructor with no arguments when you have no way to initialize the output field in it and only leave the one with arguments.
I’ve written two java desktop applications. One of them(I call it launcher) starts another(client) application.
Both applications were compiled under java 1.6.0_32 [oracle jvm, hot spot].
The Exception handler was specified in the main thread of client app.
When the launcher is started under java 1.6.0_32 everything is OK,
But when it started under 1.7x_xx and later, the exception handler begin work unproperly.
It does not catch any exceptions.
I have write the test example, the source code was listed
The launcher app source:
Start.java:
import javax.swing.*;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Start {
private ClassLoader classLoader;
private List<URL> urls = new ArrayList<URL>();
private LauncherFrame launcherFrame = new LauncherFrame();
private Start() {
urls = generateUrls();
}
public static void main(String[] args) {
new Start().initClassLoader(args);
}
public void initClassLoader(String[] args) {
launcherFrame.initComponents();
this.classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), Start.class.getClassLoader());
try {
Class<?> mainClass = classLoader.loadClass("my.example.Runner");
Object instance = mainClass.newInstance();
Method runMethod = mainClass.getMethod("run", null);
runMethod.invoke(instance);
} catch (Exception e) {
System.out.println("exception: ");
e.printStackTrace();
}
}
public List<URL> generateUrls() {
File jarFile = new File("prog2.jar");
List<URL> urls = new ArrayList<URL>();
if (jarFile.exists()) {
try {
urls.add(jarFile.toURI().toURL());
} catch (MalformedURLException e) {
}
}
return urls;
}
class LauncherFrame extends JFrame {
public void initComponents() {
// if i comment next line, everything works fine in java 6 and 7
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
}
}
}
The client app source(prog2.jar):
Runner.java:
package my.example;
public class Runner {
public static void main(String args[]) {
new Runner().run();
}
public void run() {
ThreadGroup exceptionHandler = new ThreadGroup("Global Exception Handler") {
#Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("UncaughtException method called");
e.printStackTrace();
}
};
Runnable runnable = new MainThread();
Thread thread = new Thread(exceptionHandler, runnable);
thread.start();
}
}
MainThread.java:
package my.example;
import java.awt.*;
public class MainThread implements Runnable {
public void run() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new MyQueue());
MainFrame w = new MainFrame();
w.open();
}
public class MyQueue extends EventQueue {
protected void dispatchEvent(AWTEvent event) {
super.dispatchEvent(event);
}
}
}
MainFrame.java:
package my.example;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
public class MainFrame extends WindowAdapter {
private JFrame frame;
public MainFrame() {
frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(new Dimension(200, 200));
JPanel panel = new JPanel();
JButton button = new JButton("BREAK THIS");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakThis();
}
});
panel.add(button);
frame.setContentPane(panel);
}
public void breakThis() {
throw new RuntimeException("EXCEPTION OF CLICK");
}
public void open() {
this.frame.setVisible(true);
}
}