I've built a simple client and server for a project, using a very basic text interface for testing and development (code demonstrating usage below).
The client library has an acceptMessage() method and a getMessage() method, which basically push messages into or pull messages out of a blockingQueue for input and output respectively (in the client this is implemented with put() and take() calls). One thread blocks on System.in and sends read lines to the client via acceptMessage whilst the other blocks on the client getMessage() method and echoes messages to System.out when they arrive. All very basic but it works okay.
Now that I've gotten my client library to work I'm trying to figure out how to integrate it into an application that uses a Swing GUI. So far I've not got much further than building a simple form in the interface building tool in Netbeans, with a text input box and a label. The idea is for the text input box to take the place of reading from system.in and the label to display what would have otherwise been written to system.out. By that point I'll have replicated my simple test app in Swing.
From what I understand, everything that interacts with a Swing GUI directly has to run in the Swing thread, but the client is built to run as its own thread. I don't think sending a message to acceptMessage() from the GUI will be terribly difficult (I think it involves setting up an ActionPerformed method that will read the contents of the input box and call acceptMessage() on the client, though I'm still trying to figure it out), but I have no idea how to go about getting responses back. I know I can't have the client invoke functionality in the GUI thread because of thread safety issues, and besides the client library is written in such a way as to not know anything about its consuming class. A client instance is simply passed into the consuming class which then uses acceptMessage() and getMessage() to send and receive messages. It does not (and should not) care what the consuming class actually is.
Is it possible with this architecture to easily integrate the client into the GUI? If so, what's the correct way of handling input from the client? (Like I said, I think output to the client isn't going to be especially difficult once I've figured out that aspect of Swing).
My primary motivation for using Swing is that a) it seems to be the best documented GUI library for Java, b) Netbeans already has tools for working with Swing and c) I have a rigid deadline and don't have time to switch GUI libraries and start from scratch (this is for a university project). Had I more time I'd have probably looked into other libraries, but I imagine they'd all have their own sets of quirks as well.
import java.io.*;
import java.util.logging.*;
public class TestApp implements Runnable {
private Client <String> client = null;
private UpstreamChannel upstream = null;
private DownstreamChannel downstream = null;
private Thread upstreamThread = null;
private Thread downstreamThread = null;
private boolean ending = false;
private class UpstreamChannel implements Runnable {
private TestApp outer = null;
#Override
public void run () {
Thread.currentThread ().setName ("TestApp.UpstreamChannel");
try (BufferedReader inReader = new BufferedReader (new InputStreamReader (System.in))) {
while (!this.outer.ending) {
this.outer.client.acceptMessage (inReader.readLine ());
}
} catch (IOException ex) {
Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
} finally {
this.outer.ending = true;
this.outer.downstreamThread.interrupt ();
Thread.currentThread ().interrupt ();
return;
}
}
public UpstreamChannel (TestApp app) {
this.outer = app;
}
}
private class DownstreamChannel implements Runnable {
private TestApp outer = null;
#Override
public void run () {
Thread.currentThread ().setName ("TestApp.DownstreamChannel");
try {
while (!this.outer.ending) {
System.out.println (this.outer.client.getMessage ());
}
} catch (InterruptedException ex) {
Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, ex.getMessage (), ex);
} finally {
this.outer.ending = true;
this.outer.upstreamThread.interrupt ();
Thread.currentThread ().interrupt ();
return;
}
}
public DownstreamChannel (TestApp app) {
this.outer = app;
}
}
#Override
public void run () {
if ((null == this.upstreamThread)
&& (null == this.downstreamThread)) {
this.upstreamThread = new Thread (this.upstream);
this.downstreamThread = new Thread (this.downstream);
this.upstreamThread.start ();
this.downstreamThread.start ();
try {
this.upstreamThread.join ();
this.downstreamThread.join ();
} catch (InterruptedException ex) {
Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, ex.getMessage (), ex);
} finally {
this.upstreamThread.interrupt ();
this.downstreamThread.interrupt ();
System.out.println ("Sayonara");
}
}
}
public TestApp (Client <String> client) {
this.upstream = new UpstreamChannel (this);
this.downstream = new DownstreamChannel (this);
this.client = client;
Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, "Class instantiated");
}
}
The code for starting the client app is as follows:
public static void main (String[] args) throws UnknownHostException, IOException, InterruptedException {
Client <String> clientInstance = new Client ("localhost", 8113);
TestApp app = new TestApp (clientInstance);
Thread clientThread = new Thread (clientInstance);
Thread appThread = new Thread (app);
clientThread.start ();
appThread.start ();
clientThread.join ();
appThread.interrupt ();
System.exit (0);
}
}
EDIT: I thought a worker thread that polls getMessage (and therefore blocks until a message arrives) and uses publish() to make it available would be a solution, but I think there's a risk of messages getting "dropped on the floor" if two messages arrive in quick succession.
SwingWorker reader = new SwingWorker () {
#Override
protected Object doInBackground () throws Exception {
while (!this.isCancelled ()) {
publish (clientInstance.getMessage ());
}
return null;
}
};
So your basic problem is how to get
while (!this.outer.ending) {
System.out.println (this.outer.client.getMessage ());
}
to set the text on a label instead of printing to stdout. You're right that since this is a separate thread, you can't call a method directly on a GUI widget. But you can ask the GUI thread to dispatch some code that will get run in the GUI thread,
while (!this.outer.ending) {
final String message = this.outer.client.getMessage ();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
theLabel.setText(message);
}
});
}
The other way around might be as easy as having an event handler in your GUI call
this.outer.client.acceptMessage (textBox.getText());
However if acceptMessage is also a blocking call, you need a separate thread here as well, and have the GUI communicate the message over to that thread.
I personally like to follow something like this in your actionPerformed method:
public void actionPerformed( ActionEvent event ) {
Promise<SomeReturn> promise = server.acceptMessage( message, SomeReturn.class );
promise.onSuccess( new Callback() {
public void call( SomeReturn result ) {
// this is on the swing thread
someLabel.setText( result.getText() );
}
});
}
Then this is the promise class for asynchronous operations:
public class Promise<T> {
Callback<T> successCallback;
Callback<? extends Exception> errorCallback;
// swing client will register callbacks with these methods
public onSuccess( Callback<T> callback ) {
successCallback = callback;
}
// swing client will register callbacks with these methods
public Promise<T> onError( Callback<? extends Exception> callback ) {
errorCallback = callback;
}
// network client thread will call these methods when it gets a response
public void setResult( final T result ) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
if( successCallback != null )
successCallback.call( result );
else
log.warning("Response dropped! No success callback registered " + result );
}
});
}
// network client thread will call these methods when it gets a response
public void setError( final Exception ex ) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
if( errorCallback != null )
errorCallback.call( ex );
else
log.error( ex );
}
});
}
}
I don't like using something like getMessage() because that requires a synchronous style coding where the swing client has to poll or know when to call getMessage() so that it won't block the thread. Instead why not let the thread performing the work call you back when a response arrives. It does that by calling setResult() or setError() on the Promise it returned. You request another thread to perform an action by calling acceptMessage(), then it returns to you a Promise. You can register with that promise to be notified when that message is processed (either success or error).
In Java SE API we have Future which is really close to this idea of Promise, but unfortunately they didn't provide a callback mechanisms to be notified when the result arrives. It's tremendously disappointing the API authors didn't do that because the interface they created is pretty much useless.
Behind the acceptMessage() implementation could be lots of things. You could spin up a thread passing the message and promise to it to service that message, or you could drop the message + promise onto a queue that a consumer thread or thread pool draws from. When it finishes processing the message it uses the promise to call back to your UI.
Related
Is it possible in java to create a thread that will always work in the background? The problem is that the application instance sometimes crashes with an OutOfMemoryException. Therefore, several instances are launched in parallel. Each instance does some work: it saves something to the database at the request of the user. And the stream, which should work constantly, will look into the database and somehow process the information from it.
Most likely, the sheduler will not work, since the thread must be running constantly and wait for a signal to start working.
First of all, I suggest you investigate and resolve the OutOfMemoryException because it better to avoid these cases. You can instanziate a thread that wait for a request, execute a request and then return to wait for another request. The implementation is like this for thread:
/** Squares integers. */
public class Squarer {
private final BlockingQueue<Integer> in;
private final BlockingQueue<SquareResult> out;
public Squarer(BlockingQueue<Integer> requests,
BlockingQueue<SquareResult> replies) {
this.in = requests;
this.out = replies;
}
public void start() {
new Thread(new Runnable() {
public void run() {
while (true) {
try {
// block until a request arrives
int x = in.take();
// compute the answer and send it back
int y = x * x;
out.put(new SquareResult(x, y));
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}).start();
}
}
And for the caller method:
public static void main(String[] args) {
BlockingQueue<Integer> requests = new LinkedBlockingQueue<>();
BlockingQueue<SquareResult> replies = new LinkedBlockingQueue<>();
Squarer squarer = new Squarer(requests, replies);
squarer.start();
try {
// make a request
requests.put(42);
// ... maybe do something concurrently ...
// read the reply
System.out.println(replies.take());
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
To more information, you can start to read the post that I found here to provide you the example.
You basically need an infinitely running thread with some control.
I found this answer to be the simplest and it does what you need.
https://stackoverflow.com/a/2854890/11226302
I have a test that is blocking (first block of code). I have a few elements that are all working together. I have a blocking queue that I put events on to, then I have a consumer that takes them off and sends them to Amazon Kinesis. I am pretty sure that my test is getting blocked because the queue is blocking my consumer even though I thought it was running on a separate thread.
// Test.java
#Test
public void testWhileLoop() throws InterruptedException {
ArrayBlockingQueue<Event> testQ = new ArrayBlockingQueue<Event>(1024);
// mockKinesis is a mock at the class level.
KPLPoster kpl = new KPLPoster("TestStream", mockKinesis, testQ);
Event event = new Event("TestMessage", "TestPartition");
ListenableFuture<UserRecordResult> fakeReturn = Mockito.mock(ListenableFuture.class);
final AtomicInteger numberOfWhileLoops = new AtomicInteger();
Mockito.doAnswer(invocation -> {
numberOfWhileLoops.incrementAndGet();
return fakeReturn;
})
.when(mockKinesis)
.addUserRecord("TestStream", "TestPartition", ByteBuffer.wrap("TestMessage".getBytes()));
kpl.run(); // Hangs here
for(int i = 100; i > 0; i--){
testQ.put(event);
}
kpl.stop();
kpl = null;
assert(numberOfWhileLoops.toString()).equals("100");
}
Here is the run method of BaseKinesisPoster which my KPLPoster inherits. It should be noted that BaseKinesisPoster implements the Runnable interface.
//BaseKinesisPoster.java
#Override
public void run() {
shutdown = false;
while (!shutdown && !(Thread.currentThread().isInterrupted())) {
try {
this.runOnce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}catch (Exception e){
e.printStackTrace();
}
}
}
Finally, here is part of my KPLPoster's (which extends BaseKinesisPoster) relevant runOnce() method.
// KPLPoster.java
#Override
protected void runOnce() throws Exception {
Event event = inputQueue.take();
//other stuff in my method
}
How do I make sure that blocking on my queue consumer doesn't block my test/main thread?
When you call
Thread.run();
it invokes the method called. Nothing special happens and the method is run in the current thread.
When you call
Thread.start();
This starts the thread which in turn calls run() in that new thread.
BTW Thread.stop() will throw an UnsupportedOperationException in Java 8. You shouldn't use it. You should allow it to finish naturally.
Code -> http://pastebin.com/1PFCGWQy
Blocks that I'm having problems with
class ClientSender implements Runnable {
Socket server;
ServerClientFrontEnd SCFE;
public ClientSender(Socket server, ServerClientFrontEnd SCFE){
this.server = server;
this.SCFE = SCFE;
}
public void run(){
try(ObjectOutputStream out = new ObjectOutputStream(server.getOutputStream())){
//System.out.println("Client chat ver. 0.1");
//Scanner get = new Scanner(System.in);
while(!server.isClosed()){
//System.out.print("YOU:");
if(!SCFE.synchronizedOutputCollection.isEmpty()) // Here
{
logger.info("Has made it to ClientSender!");
String string = SCFE.synchronizedOutputCollection.firstElement();
logger.info(string);
out.writeObject(string); // Here
logger.info("Output Queue: " + SCFE.synchronizedOutputCollection.toString());
}
//else{ logger.info("It failed the conditional"); }
}
} catch (IOException ex) {
//logger.info("Closing connection...");
//System.exit(0);
}
}
}
class ClientReceiver implements Runnable {
Socket server;
ServerClientFrontEnd SCFE;
public ClientReceiver(Socket server, ServerClientFrontEnd SCFE){
this.server = server;
this.SCFE = SCFE;
}
public void run(){
try(ObjectInputStream in = new ObjectInputStream(server.getInputStream())){
while(!server.isClosed()){
SCFE.ChatBox.setText(SCFE.ChatBox.getText() + "\nOTHER: " + (String) in.readObject()); //Here
logger.info("Receiver has read object!");
}
} catch (IOException ex) {
logger.info("Closing connection");
System.exit(0);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
For some reason, I can not get this to work. I already got it working on a command-line environment, quite perfectly, but I wanted to port it to a graphical user interface and this problem has had me stumped for more than on hour. I didn't know how to handle the fact that Client's original class called other threads which I needed to send and receive the information to and from the server.
Basically, my program works by having the client connect to the server via a ServerSocket, which THEN processes each request. Of course, I've just recently learned about sockets on Thursday but I wanted to make a program of my own... anyway, moving on, the problem is with the ServerClientFrontEnd Class, which for some reason, and I don't know how for the life of me, the collection I'm using to get the inputted text either remains empty or it just will not read from it.
Maybe it might have to do with my while loop, but it worked perfectly before. I have a TON of loggers everywhere to log everything, and if I add an else statement when it checks if the collection is empty, it definitely activates the else statement repeatedly, EVEN AFTER the synchronizedOutputCollection was given a value. In fact, I even print the value inside of the collection when the send button is pressed. In fact, when I attempt a similar print statement inside the thread, the collection is empty and it remains empty.
How can I share a synchronized collection of objects among threads? This question is plaguing me and I would really appreciate a reply.
Also this is runnable, you just have to activate server and 2 clients to test it. P.S I have tried BlockingQueues but they make the GUI thread to freeze up because the queue is never read from, causing a deadlock.
As #markspace pointed out in a comment you have lots of funny things going on in your code. You should take a step backward, go back to the command line interface and rework your entire class structure. Remove those inner classes, use some interfaces like MessageListener or ConnectionListnener that your client or server uses to talk to other classes (like your GUI) about things like messages received or connection created/lost.
When you get done your client main method should look very simple:
public static void main(String [] args) {
Client client = new Client("127.0.0.1");
client.addMessageListener(new MessageListener() {
public void messageRecieved(String message) {
System.out.println(message);
}
});
client.connect();
System.out.println("Connected to server.");
Scanner scanner = new Scanner(System.in);
String userInput = null;
boolean quit = false;
do {
userInput = scanner.readLine();
if(userInput != null && userInput.equals("quit")) {
client.sendMessage(userInput);
} else {
quit = true;
}
} while(!quit);
}
Of course I just made this up but its just an example of once you have your class structure properly broken out and things where they should be it will be very easy to hook a GUI up.
The list could go on but bottom line is you need to take a hard look at what classes need to know what information and why. Break apart classes and make fields private and dont share information unless they need to be shared! Its important that you really think about reducing code coupling.
Any way enough rambling and onto the actual problem with your code: in ServerClientFrontEnd.main you have this snipplet:
new ServerClientFrontEnd().startClient();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ServerClientFrontEnd().setVisible(true);
}
});
You are creating 2 instances of ServerClientFrontEnd, one that starts the client the other that shows the GUI. The one that shows the GUI is the one where you change the List of strings and the other list is always empty. To make it work change the snipplet to read:
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
ServerClientFrontEnd fontEnd = new ServerClientFrontEnd();
fontEnd.startClient();
fontEnd.setVisible(true);
}
});
I am working on a relatively simple DB manager, that takes in a number of files, parses and catalogs the information in a particular fashion. I also wrote a simple GUI in Swing for this purpose. In order to speed up the process I want to implement multithreading to the parallelizable parts of the execution in order to speed up the program.
The below code sits in a class called FDBCreatePanel, a custom JPanel, that sits in a FDBManagerFrame which accommodates the main method.
private void dbCreateActionButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dbCreateActionButtonActionPerformed
jfc = new JFileChooser();
jfc.setVisible(true);
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int returnVal = jfc.showSaveDialog(null);
((FDBManagerFrame) SwingUtilities.getRoot(this)).startProcessAnimation();
if(returnVal == JFileChooser.APPROVE_OPTION) {
new SwingWorker<Void,Void>(){
#Override
protected Void doInBackground() throws Exception {
File dir = jfc.getSelectedFile();
DbManager dbm = new DbManager(dir, dbNameField.getText());
try{
dbm.doTimeConsumingStuff();
} catch (SQLException e){
// errorhandling
}
#Override
protected void done() {
((FDBManagerFrame) SwingUtilities.getRoot(FDBCreatePanel.this)).endProcessAnimation();
}
}.execute();
}
}
The time consuming method in DbManager class leads to (among others) the following bits of code in the ParserType1 class:
private void init() {
try {
this.reader = new LineNumberReader(new FileReader(this.datfile));
Thread t = new Thread(new Runnable(){
#Override
public void run() {
Entry e;
while((e = parseNextEntry()) != null)
queue.offer(e);
}
}, "t1-parser-thread");
t.run();
} catch (FileNotFoundException e) {
// error handling
}
}
I do not see any t1-parser-thread(s) in JVisualVM when I monitor the execution of my program. It appears as if my code executes entirely on a single thread, ignoring the initiation of new threads. Am I missing something with respect to threading and Swing?
You're calling run() on the newly created Thread object in ParserType1.init(). That doesn't start a new thread - it just execute's the thread's run() method in the existing thread. You should be calling start() instead.
Fundamentally I think it was a mistake for Thread to implement Runnable at all - the distinction between "this is the code that should be executed" (Runnable) and "this is the way I'm going to execute it" (Thread) has been unfortunately blurred. The fact that Thread can also compose a Runnable makes it even worse.
Runnable runnable = new Runnable() { ... };
Thread thread = new Thread(runnable) {
// Override run here...
};
Unless your overridden run method calls super.run(), the Runnable passed into the constructor is ignored. Crazy stuff. Thread should (IMO) be final, not implement Runnable, and force you to provide a Runnable at construction. It's far too late to change now, unfortunately :(
Basically, you should never be calling run() on a Thread. At least, I can't remember the last time I saw that without it being a bug.
As Jon Pointed out you want to call the start() method to actually spawn a new Thread which will call the run method of your inline Runnable. If you just call run it is like you called any other method and it will execute in the same Thread.
}, "t1-parser-thread");
t.start();
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
I am a newbie to vert.x. I was trying out the vert.x "NetServer" capability. http://vertx.io/core_manual_java.html#writing-tcp-servers-and-clients and it works like a charm .
However , I also read that "A verticle instance is strictly single threaded.
If you create a simple TCP server and deploy a single instance of it then all the handlers for that server are always executed on the same event loop (thread)."
Currently, for my implementation, I wanted to receive the TCP stream of bytes and then trigger another component. But this should not be a blocking call within the "start" method of the Verticle. So, is it a good practice, to write an executor within the start method? or does vertx automatically handle such cases.
Here is a snippet
public class TCPListener extends Verticle {
public void start(){
NetServer server = vertx.createNetServer();
server.connectHandler(new Handler<NetSocket>() {
public void handle(NetSocket sock) {
container.logger().info("A client has connected");
sock.dataHandler(new Handler<Buffer>() {
public void handle(Buffer buffer) {
container.logger().info("I received " + buffer.length() + " bytes of data");
container.logger().info("I received " + new String(buffer.getBytes()));
//Trigger another component here. SHould be done in a sperate thread.
//The previous call should be returned . No need to wait for component response.
}
});
}
}).listen(1234, "host");
}
}
What should be mechanism to make this a non blocking call.
I don't think this is the way to go for vert.x.
A better way would be to use the event bus properly instead of Executor. Have a worker respond to the event on the bus, do the processing, and signal the bus when it's completed.
Creating threads defeats the purpose of going with vert.x.
The most flexible way is to create an ExecutorService and process requests with it. This brings fine-grained control over threading model of workers (fixed or variable number of threads, what work should be performed serially on a single thread, etc).
Modified sample might look like this:
public class TCPListener extends Verticle {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public void start(){
NetServer server = vertx.createNetServer();
server.connectHandler(new Handler<NetSocket>() {
public void handle(final NetSocket sock) { // <-- Note 'final' here
container.logger().info("A client has connected");
sock.dataHandler(new Handler<Buffer>() {
public void handle(final Buffer buffer) { // <-- Note 'final' here
//Trigger another component here. SHould be done in a sperate thread.
//The previous call should be returned . No need to wait for component response.
executor.submit(new Runnable() {
public void run() {
//It's okay to read buffer data here
//and use sock.write() if necessary
container.logger().info("I received " + buffer.length() + " bytes of data");
container.logger().info("I received " + new String(buffer.getBytes()));
}
}
}
});
}
}).listen(1234, "host");
}
}
As duffymo mentioned creating threads defeats the purpose of using vertx. Best way would be to write a message into eventbus and create a new handler listening for messages from the eventbus. Updated the code to showcase this. Writing the messages to "next.topic" topic, and registered a handler to read message from "next.topic" topic.
public class TCPListener extends Verticle {
public void start(){
NetServer server = vertx.createNetServer();
server.connectHandler(new Handler<NetSocket>() {
public void handle(NetSocket sock) {
container.logger().info("A client has connected");
sock.dataHandler(new Handler<Buffer>() {
public void handle(Buffer buffer) {
String recvMesg = new String(buffer.getBytes());
container.logger().info("I received " + buffer.length() + " bytes of data");
container.logger().info("I received " + recvMesg);
//Writing received message to event bus
vertx.eventBus().send("next.topic", recvMesg);
}
});
}
}).listen(1234, "host");
//Registering new handler listening to "next.topic" topic on event bus
vertx.eventBus().registerHandler("next.topic", new Handler<Message<String>() {
public void handle(Message<String> mesg) {
container.logger.info("Received message: "+mesg.body());
}
};
}
}