Running java Application with Multiple UI Threads - java

I'm trying to coding a very simple Client-Server Email project in java.
I've already code the communication between client and server using socket and now I'm tryng to code some test which includes also a very simple UI.
My idea is to create many threads as many clients I have and I want that every sigle thread starts opening a simple UI window created with Java FX but I have some problems.
This is the main class:
import java.io.*;
public class ClientController{
public static void main(String args[]) throws IOException {
ParallelClient c1=new ParallelClient("aaaa#gmail.com");
ParallelClient c2=new ParallelClient("bbbb#gmail.com");
c1.start();
c2.start();
}
}
This is the ParallelClient class:
import ...
public class ParallelClient extends Thread{
private String user;
public ParallelClient(String user){
this.user=user;
}
public void run(){
ClientApp app=new ClientApp();
try {
app.start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
...
}
...
}
And this is the ClientApp class which set the new window:
import ...
public class ClientApp extends Application {
#Override
public void start(Stage stage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("ui/client-management.fxml"));
stage.setTitle("ClientMail");
stage.setScene(new Scene(root, 1080, 720));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I try to run the code I get the followung problem and I can't understand how to fix it:
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.NoClassDefFoundError: Could not initialize class javafx.stage.Screen
at javafx.stage.Window.<init>(Window.java:1439)
at javafx.stage.Stage.<init>(Stage.java:252)
at javafx.stage.Stage.<init>(Stage.java:240)
at model.ParallelClient.run(ParallelClient.java:25)
java.lang.ExceptionInInitializerError
at javafx.stage.Window.<init>(Window.java:1439)
at javafx.stage.Stage.<init>(Stage.java:252)
at javafx.stage.Stage.<init>(Stage.java:240)
at model.ParallelClient.run(ParallelClient.java:25)
Caused by: java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = Thread-1
at com.sun.glass.ui.Application.checkEventThread(Application.java:441)
at com.sun.glass.ui.Screen.setEventHandler(Screen.java:369)
at com.sun.javafx.tk.quantum.QuantumToolkit.setScreenConfigurationListener(QuantumToolkit.java:728)
at javafx.stage.Screen.<clinit>(Screen.java:74)
... 4 more

There are several problems with the structure of the application as you have posted it in the question.
The Application class represents the lifecycle of the entire application, which is managed via calls to its init(), start() and stop() methods. There should be only one Application instance in the entire application, and typically this instance is created by the JavaFX startup mechanism so you should not instantiate the Application subclass yourself.
JavaFX applications require the JavaFX runtime to be started, which includes launching the JavaFX Application Thread. This is done via a call to the static Application.launch() method, which must be called only once. The launch() method starts the JavaFX runtime, creates the instance of the Application class, calls init(), and then calls start() on the FX Application Thread. (In JavaFX 9 and later, you can also start the runtime by calling Platform.startup(), but use cases for this are rare).
Note that in your application, there is no call to Application.launch() (or Platform.startup()), so the JavaFX runtime is never started.
Certain operations can only be performed on the FX Application Thread. These include creating Stages and Scenes, and any modifications of properties of UI elements that are already displayed. Thus you cannot "run each client" in a separate thread. This is the cause of your exception: you are trying to create a new Stage on a thread that is not the FX Application Thread.
Each client does not need a new thread to display the UI (and, as described above, cannot do that). You likely do need to perform each client's communication with the server on a separate thread (because those are operations that take a long time, and you should not block the FX Application thread). You can do that by creating a new thread for each client's server communication, or using a shared executor service so that each client can get a thread from a pool (this is probably the preferred approach).
So your structure should look something like this:
public class Client {
private Parent ui ;
private ExecutorService exec ; // for handling server communication
private final String user ;
public Client(String user, ExecutorService exec) {
this.user = user ;
this.exec = exec ;
try {
ui = FXMLLoader.load(getClass().getResource("ui/client-management.fxml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public Client(String user) {
this(user, Executors.newSingleThreadExecutor());
}
public Parent getUI() {
return ui ;
}
public void showInNewWindow() {
Scene scene = new Scene(ui);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
}
public void checkForNewEmail() {
Task<List<Email>> newEmailTask = new Task<>() {
#Override
protected List<Email> call() throws Exception {
List<Email> newEmails = new ArrayList<>();
// contact server and retrieve any new emails
return newEmails ;
}
};
newEmailTask.setOnSucceeded(e -> {
List<Email> newEmails = newEmailTask.getValue();
// update UI with new emails...
});
exec.submit(newEmailTask);
}
// etc ...
}
Then your ClientController class could do something like this:
public class ClientController {
private ExecutorService exec = Executors.newCachedThreadPool();
public void startClients() {
Client clientA = new Client("aaaa#gmail.com", exec);
Client clientB = new Client("bbbb#gmail.com", exec);
clientA.showInNewWindow();
clientB.showInNewWindow();
}
}
and your app class can do
public class ClientApp extends Application {
#Override
public void start(Stage primaryStage) {
ClientController controller = new ClientController();
controller.startClients();
}
public static void main(String[] args) {
Application.launch(args);
}
}

Related

JavaFx Task EventHandler handled in which Thread

For JavaFX UI node, if I register an event handler:
final MenuItem buyItem = new MenuItem("Buy");
buyItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String symbol = row.getItem().getSymbol();
String instrumentID = row.getItem().getInstrumentID();
.....
}
);
I can assume code inside handle() will always be executed in JavaFX application Thread, so there is no need to wrap them inside Platform. runLater.
But when I work with javafx.concurrent.Task:
import javafx.concurrent.Task;
public class BuyTask extends Task<Map<String, Object>> {
......
}
BuyTask buyTask = new BuyTask(this.api, params);
Thread buyThread = new Thread(buyTask);
buyThread.start();
buyTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(final WorkerStateEvent workerStateEvent) {
Map<String, Object> result = (Map) workerStateEvent.getSource().getValue();
.......
Platform.runLater(new Runnable() {
#Override public void run() {
portfolioService.restart();
}
});
}
}
In which thread is the task's event handler executed in? As I need to do perform restart on a javafx.concurrent.ScheduledService -> portfolioService.restart() which mentioned must be done in JavaFX Application Thread, I wrap it inside Platform.runLater.
But is it required? Will this task event handler always being executed in JavaFX Application Thread as well? Thanks!
The JavaFX documentation for Task has the answer:
Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to its public properties, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread.
So - no, there is no need to wrap the call with Platform.runLater.

Implement JUnit test for SNMP server and client

I found very good example for SNMP server and SNMP client but I'm not sure how I can implement JUnit test into single test file:
public class SNMPClientTest
{
#Test
public void randomData()
{
SnmpTrap trap = new SnmpTrap("127.0.0.1",
"1.3.6.1.4.1.2789.2005.1={s}WWW Server Has Been Restarted",
2, "kschmidt", "MD5", "mysecretpass", "DES", "mypassphrase");
trap.doTrap();
}
}
public class SNMPServerTest
{
#Test
public void randomDatabaseData() throws SQLException, FileNotFoundException, IOException
{
V3TrapReceiver v3 = new V3TrapReceiver("127.0.0.1", "kschmidt", "MD5",
"mysecretpass", "DES", "mypassphrase");
v3.listen();
}
}
When I run the server I get message Waiting for traps.. and I can't continue the JUnit test. But I can run them into 2 separate files.
How I can solve this? You can find the complete source code here: http://pastebin.com/zKEtXQmq
If you wanted to have both the client and the server running within the same test you can consider starting them as separate Threads within a single Test.
I normally try to avoid this because it does add some complexity and context management to the test.
Please note:
This sample has not been tested, there may be tweaks that need to be made. The gist of the handling of the additional threads should be about right.
I did not verify anything for your tests, so all this does is run the server and then the client with no expectation of output or state.
#Rule
public ErrorCollector collector = new ErrorCollector();
#Rule
public Timeout testTimeout = new Timeout(15, TimeUnit.SECONDS);
#Test
public void testServerClientCommunication throws Exception () {
final SnmpTrap trap = new SnmpTrap("127.0.0.1",
"1.3.6.1.4.1.2789.2005.1={s}WWW Server Has Been Restarted",
2, "kschmidt", "MD5", "mysecretpass", "DES", "mypassphrase");
final V3TrapReceiver v3 = new V3TrapReceiver("127.0.0.1", "kschmidt", "MD5",
"mysecretpass", "DES", "mypassphrase");
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
v3.listen();
}
} catch (Throwable th) {
//Exceptions thrown outside of the main Junit execution won't get propagated back to fail the test
//Use the ErrorCollector to maintain awareness
collector.addError(th);
}
}};
//Create the Thread to handle the Server execution
final Thread serverExecutor = new Thread(serverTask, "SNMP Server");
/*
* Create the client task and thread.
*/
Runnable clientTask = new Runnable() {
#Override
public void run() {
try {
boolean clientIsDone = false;
while (!clientIsDone) {
trap.doTrap();
//FIXME: Determine the state that matters.
clientIsDone = true;
}
} catch (Throwable th) {
//Exceptions thrown outside of the main Junit execution won't get propagated back to fail the test
//Use the ErrorCollector to maintain awareness
collector.addError(th);
}
}};
Thread clientExecutor = new Thread(clientTask, "SNMP Client");
/*
* Start the server first
*/
//Don't hold the JVM if the server is not done.
serverExecutor.setDaemon(true);
serverExecutor.start();
/*
* Now start the client. Note that after the client traps successfully that it will interrupt the server thread.
* The intent is that the interrupt will allow the server thread to die gracefully
*/
clientExecutor.setDaemon(true);
clientExecutor.start();
//Since we off-threaded the tasks the test will consider itself 'done' unless we join with the client, which basically says
//"Hold the current thread at this point until the other thread completes."
clientExecutor.join();
}
Start the server in a method annotated with #BeforeClass. This will run before any other tests will be invoked.

Stopping a running process via GUI, in java

I have a GUI program that executes TestNG automation scripts. It's meant for users to easily configure some setting and launch the automation script that they want.
One thing I need to add is the ability to instantly stop the running TestNG process. Something like how in Eclipse, the 'Terminate' button will instantly stop whatever is running.
This is what the code that launches the TestNG tests looks like:
public class ScriptRunner implements Runnable {
public void runScript() {
Thread testRun = new Thread(this);
testRun.start();
}
#Override
public void run() {
//various other things are configured for this,
//but they're not relevant so I left them out
TestNG tng = new TestNG();
//While this runs, various browser windows are open,
//and it could take several minutes for it all to finish
tng.run();
}
}
As per the comment, the tng.run() can take several minutes to complete, and it's performing several things, opening/closing browser windows, etc.
How can I just instantly terminate the process, like you would when running an application from an IDE?
EDIT:
Per the comments, I'm attempting to use a ServiceExecutor and shutDownNow() The code is looking like this:
ExecutorService executorService = Executors.newFixedThreadPool(10);
public void runScript() {
executorService.execute(this);
}
//this method gets called when I click the "stop" button
public void stopRun() {
executorService.shutdownNow();
}
#Override
public void run() {
//same stuff as from earlier code
}
Spawn a child JVM process using ProcessBuilder or Runtime and you will be able to terminate that process when the user requests that the script stops running.
You can use ExecutorService to start test execution into one another thread. You can choose to have many thread in parrallel or juste one thread for all tests in sequence by choosing which executor service you need.
After that, start the execution of all tests in the same executor service instance by calling submit() method on it. You can stop the execution of all submitted runnables by calling shutdownNow() method.
It is important to use the same instance of ExecutorService, otherwise you start each test in a different thread and you will not enable to break the execution chain (or by calling shutdownNow() on all of them).
I was recently working on the executor framework. Here I have listed my problem
http://programtalk.com/java/executorservice-not-shutting-down/
Be careful if you are doing some IO operations the executor service may not shutdown immediately. If you see the below code stopThread is important because it tells your program that the thread has been asked to stop. And you can stop some iteration what you are doing.
I will modify your code like this:
public class MyClass {
private ExecutorService executorService;
private boolean stopThread = false;
public void start() {
// gives name to threads
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("thread-%d").build();
executorService = Executors.newSingleThreadExecutor(factory);
executorService.execute(new Runnable() {
#Override
public void run() {
try {
doTask();
} catch (Exception e) {
logger.error("indexing failed", e);
}
}
});
executorService.shutdown();
}
private void doTask() {
logger.info("start reindexing of my objects");
List<MyObjects> listOfMyObjects = new MyClass().getMyObjects();
for (MyObjects myObject : listOfMyObjects) {
if(stopThread){ // this is important to stop further indexing
return;
}
DbObject dbObjects = getDataFromDB();
// do some task
}
}
public void stop() {
this.stopThread = true;
if(executorService != null){
try {
// wait 1 second for closing all threads
executorService.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
What about this,
add a volatile static boolean and make the thread code look like...
if(ScriptRunner.runThread){
//Do some stuff here
}
if(ScriptRunner.runThread){
//Do some other stuff here
}
if(ScriptRunner.runThread){
//Do some other stuff here
}
if(ScriptRunner.runThread){
//Do rest of the stuff here
}
Now you can add a button in your main GUI that simply sets the runThread to false so the thread will terminate nearly instant leaving all the leftover code untouched as you press the Stop button.
public class ScriptRunner implements Runnable {
volatile static Boolean runThread = true;
public void runScript() {
Thread testRun = new Thread(this);
testRun.start();
}
public void terminate(){
runThread = false;
}
#Override
public void run() {
//various other things are configured for this,
//but they're not relevant so I left them out
TestNG tng = new TestNG();
//While this runs, various browser windows are open,
//and it could take several minutes for it all to finish
tng.run();
}
}
How about a new Thread? You have to add an private Thread thread; in the gui and when ever you start
thread = new thread(){
#Override
public void run(){
//start process here
}
};
thread.start();
and to stop "terminate"
thread.stop();(depracted) or thread.setDeamon(true);
Everytime I have to stop a process by the gui I use this.
Hope I could help ;)
In your GUI somewhere you have something like
ScriptRunner scriptRunner = new ScriptRunner();
scriptRunner.runScript();
When you want to stop it call
scriptRunner.interrupt();
Change the code in ScriptRunner
private Thread testRun;
public void runScript() {
testRun = new Thread(this);
testRun.start();
}
public void interrupt() {
testRun.interrupt();
}
Save all created processes and kill them when your program ends:
public class ProcessFactory {
private static Set<Process> processes = new HashSet<>();
private static boolean isRunning = true;
public static synchronized Process createProcess(...) throws ... {
if (!isRunning)
throw ...
... // create your spawned process
processes.add(process);
return process;
}
public static synchronized void killAll() {
isRunning = false;
for (Process p : processes)
p.destroy();
processes.clear();
}
public static void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
void run() {
killAll();
}
});
}
}
This can be improved by adding a mechanism that removes already dead processes, but you get the general idea.

jswing running a long task

I am new to java
I have a function runner inside PhotoPoster class (PhotoPoster class is a Jframe with lots of buttons and other GUI elements)
it contains a START button when I click on START it executes the runner function which runs an activity & thats takes a very long time
and other GUI components are not accessible unless the runner functions completes.
I want this to work in separate thread or any other solution to help me
what I currently do is
I have made a another class GuiWorker.java
public class GuiWorker extends SwingWorker<Integer, Integer>{
public GuiWorker() throws IOException {
}
protected Integer doInBackground() throws Exception {
PhotoPoster photoPoster = new PhotoPoster();
photoPoster.ruuner();
return 0;
}
protected void done() {
System.out.println("done");
}
}
PhotoPoster.java
on button click
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// PhotoPoster photoPoster = new PhotoPoster();
//ruuner();
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
try {
new GuiWorker().execute();
} catch (IOException ex) {
Logger.getLogger(PhotoPoster.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
it gives system out done but not performing runner function activity
Please Help me to sort out this error or any other solution
It looks as though you are queuing your long running thread back onto the Event Dispatch Thread, which means that even though you are doing invokeLater it will still block the thread.
You need to use a SwingWorker.

How to unit test that a JavaFX application launches

I've got a JavaFX application, and I want to test if it launches or not. How would I go about doing that? Is it possible with just JUnit, or can TestFX help me in that?
My main issue is: How do I shut down the application right after it has (succesfully) launched?
Example application class:
public class MovieDB extends Application {
#Override
public void start(final Stage primaryStage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(MovieDBController.class.getResource("MovieDB.fxml"), ResourceBundle.getBundle("bundles/bundle", new Locale("en")));
Parent root = fxmlLoader.load();
Scene scene = new Scene(root, 1024, 768);
StyleManager.getInstance().addUserAgentStylesheet(getClass().getResource("/css/MovieDB.css").getPath());
primaryStage.setTitle("MovieDB");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Since the Application.launch method does not return until the application has exited, either via a call to Platform.exit or all of the application windows have been closed so you have to wrap it into another thread in order to terminate it.
If you call Platform.exit right after the JavaFX application launches you will get IllegalStateException. If you wait for a while so your JavaFX application can be initialized and then call Platform.exit, both your JavaFX application and your wrapper thread will be terminated without completing or throwing any exception. I couldn't find a way to work that out by using Platform.exit.
However, I managed to do it by using Thread.interrupt. Simply run your JavaFX application inside a wrapper thread, wait for a while and then interrupt your wrapper thread. This way the JavaFX application will be interrupted and throw InterruptedException. If it does not throw then there is an issue launching your JavaFX application.
Note that it may take longer than you wait for JVM to launch JavaFX application so this method does not guarantee that the JavaFX application is interrupted after it is properly launched which might result in a false negative situation.
Test Class
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class JavaFXTest {
// Wrapper thread updates this if
// the JavaFX application runs without a problem.
// Declared volatile to ensure that writes are visible to every thread.
private volatile boolean success = false;
/**
* Test that a JavaFX application launches.
*/
#Test
public void testMain() {
Thread thread = new Thread() { // Wrapper thread.
#Override
public void run() {
try {
Application.launch(JavaFXTest.class); // Run JavaFX application.
success = true;
} catch(Throwable t) {
if(t.getCause() != null && t.getCause().getClass().equals(InterruptedException.class)) {
// We expect to get this exception since we interrupted
// the JavaFX application.
success = true;
return;
}
// This is not the exception we are looking for so log it.
Logger.getLogger(JavaFXTest.class.getName()).log(Level.SEVERE, null, t);
}
}
};
thread.setDaemon(true);
thread.start();
try {
Thread.sleep(3000); // Wait for 3 seconds before interrupting JavaFX application
} catch(InterruptedException ex) {
// We don't care if we wake up early.
}
thread.interrupt();
try {
thread.join(1); // Wait 1 second for our wrapper thread to finish.
} catch(InterruptedException ex) {
// We don't care if we wake up early.
}
assertTrue(success);
}
}
JavaFX Application Class
import java.io.IOException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class JavaFX extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
primaryStage.setTitle("JavaFX");
Label label = new Label("Hello World!");
StackPane root = new StackPane();
root.getChildren().add(label);
primaryStage.setScene(new Scene(root, 250, 250));
primaryStage.show();
}
}
Assuming that primaryStage is the only open stage, the JavaFX thread will automatically shut down when you call primaryStage.hide(). This is because JavaFX is set by default to shutdown when all stages are hidden, which can be changed by calling Platform.setImplicitExit(false).
More info here.

Categories

Resources