Reputation: 29
i writing java program using propertychangesupport,propertychange and fireproperty change, now its working but not at all case, when i i change the value and printed it its working, but when i tried to do a while loop on the spesipic class that listen to change it just wond get out the loop when i put it in the while condition,
public class Main {
public static void main(String[] args) {
CLI cli = new CLI(System.in,System.out);
Server server = new Server(34567);
cli.addPropertyChangeListener(server);
new Thread(cli).start();
}
}
public class CLI implements Runnable{
private Scanner scanner;
private String userInput;
private PropertyChangeSupport pcs;
private Boolean serverIsRunning;
public CLI(InputStream in, OutputStream out){
this.scanner = new Scanner(in);
pcs = new PropertyChangeSupport(this);
serverIsRunning = false;
}
@Override
public void run() {
while (true) {
System.out.println("pls enter your command:");
userInput = scanner.nextLine().trim().toUpperCase();
switch (userInput) {
case "START":
if (!serverIsRunning) {
pcs.firePropertyChange(userInput, null, "START");
new Thread(new Server(34567)).start();
serverIsRunning = true;
} else {
System.out.println("server is already running");
}
break;
case "SHUTDOWN":
if (serverIsRunning) {
pcs.firePropertyChange(userInput, null, "SHUTDOWN");
serverIsRunning = false;
} else {
System.out.println("server is not running");
}
break;
}
}
}
public void addPropertyChangeListener(PropertyChangeListener pcl){
this.pcs.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl){
this.pcs.removePropertyChangeListener(pcl);
}
}
public class Server implements Runnable, PropertyChangeListener {
private int port;
private ServerSocket server;
private String userInput = "";
private Boolean serverIsRunning;
public Server(int port) {
this.port = port;
serverIsRunning = true;
}
public void propertyChange(PropertyChangeEvent evt) {
userInput = evt.getNewValue().toString();
switch (userInput) {
case "START":
System.out.println("Starting server...");
serverIsRunning = true;
break;
case "SHUTDOWN":
serverIsRunning = false;
break;
}
}
@Override
public void run() {
try {
server = new ServerSocket(port);
} catch (IOException e) { }
while (serverIsRunning) {
try {
new Thread(new Client(server.accept())).start();
} catch (IOException e) { }
}
try {
server.close();
System.out.println("shutdown");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Upvotes: 0
Views: 2007
Reputation: 285405
Again a main purpose of using a listener design pattern is to avoid having to use a while loop to continually poll for state change and instead have the listener and listener support work together to notify you when the state of an object changes.
Other issues:
fireXxx
method at the location of change of state, not any of your other classes.while (true)
loop. All it should do is listen and respond to state changes in the Bean, nothing more and nothing less.For example say your bean looked like this:
public class Bean2 {
// constant for the property change name
public static final String STATE = "state";
private PropertyChangeSupport pcs;
// this is the "bound" field
private String state = "";
public Bean2() {
pcs = new PropertyChangeSupport(this);
}
public String getState() {
return state;
}
// notify listeners within the setter
public void setState(String state) {
String oldValue = this.state;
String newValue = state;
this.state = state;
pcs.firePropertyChange(STATE, oldValue, newValue);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
// method to remove...
}
Then your listener could be as simple as:
public class Listener2 implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("From listener: state change -- new state: " + evt.getNewValue());
// this code will obviously need to do more...
}
}
and used like so:
public static void main(String[] args) {
Bean2 bean = new Bean2();
Listener2 listener = new Listener2();
bean.addPropertyChangeListener(Bean2.STATE, listener);
Scanner scanner = new Scanner(System.in);
String text = "";
while (!text.equalsIgnoreCase(EXIT)) {
System.out.print("Enter text or \"EXIT\" to quit: ");
text = scanner.nextLine();
if (!text.equalsIgnoreCase(EXIT)) {
bean.setState(text);
}
}
scanner.close();
}
See, no while loop, no calling fireXxx
out of the bean
Regarding your edits, I'm still not 100% sure of your entire program set up, but perhaps something along these lines:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class MyServer2 {
private static final String EXIT = "exit";
public static final int PORT = 4444;
private ServerSocket server;
public MyServer2() throws IOException {
server = new ServerSocket(PORT);
}
public void beanChanged(String text) {
// *** not sure what you want to do with this text
// *** other than to check that it != EXIT
if (!text.equalsIgnoreCase(EXIT)) {
try {
new Thread(new Client(server.accept()));
} catch (IOException e) {
e.printStackTrace();
}
} else {
// System.exit(0); // ????
}
}
public static void main(String[] args) {
MyServer2 server = null;
try {
server = new MyServer2();
} catch (IOException e) {
e.printStackTrace();
}
Bean2 bean = new Bean2();
Listener2 listener = new Listener2(server);
bean.addPropertyChangeListener(Bean2.STATE, listener);
Scanner scanner = new Scanner(System.in);
String text = "";
while (!text.equalsIgnoreCase(EXIT)) {
System.out.print("Enter text or \"EXIT\" to quit: ");
text = scanner.nextLine();
if (!text.equalsIgnoreCase(EXIT)) {
bean.setState(text);
}
}
scanner.close();
}
}
public class Bean2 {
// constant for the property change name
public static final String STATE = "state";
private PropertyChangeSupport pcs;
// this is the "bound" field
private String state = "";
public Bean2() {
pcs = new PropertyChangeSupport(this);
}
public String getState() {
return state;
}
// notify listeners within the setter
public void setState(String state) {
String oldValue = this.state;
String newValue = state;
this.state = state;
pcs.firePropertyChange(STATE, oldValue, newValue);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
// method to remove...
}
public class Listener2 implements PropertyChangeListener {
private MyServer2 myServer2;
public Listener2(MyServer2 myServer2) {
this.myServer2 = myServer2;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
// notify server by calling its public method with new value
myServer2.beanChanged((String) evt.getNewValue());
}
}
public class Client implements Runnable {
private Socket socket;
public Client(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// TODO finish coding
}
}
But this still feels awkward. Note that I usually will put my code to accept()
a new client in its own thread, since it is blocking code, something like:
new Thread(() -> {
while (true) {
try {
new Thread(new Client(server.accept()));
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Upvotes: 2