Code sample:
#SpringBootApplication
public class Launcher {
public static void main(String[] args) {
System.out.println("Server Started!");
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Launcher.class)
.headless(false).run(args);
ctx.getBean(Launcher.class);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Administration(ctx).setVisible(true);
}
});
}
}
When the Administration class runs , will it have a valid context ? I want to pass the context inside Administration so that I can call some of the services that is provided. If this doesn't work, how can I access the services from a thread that is not in it's context ?
Related
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);
}
}
I am trying to use an Apache Camel interface called a Processor and am running into some difficulties. I was expected the messages to 1) be sent to the ActiveMQ queues in the JBoss Fuse application server, 2) be processed by the Camel Processor, and then 3) be sent to a different Queue specified in the source-code. What happens now is that the SOP statements in main print and some error messages on Logging but nothing is sent to the queues from the program.
Here is my code:
/* create a Camel processor */
package foo;
import org.apache.camel.Processor;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
public class MyOwnProcessor implements Processor {
//main
public static void main(String[] args) {
System.out.println("Starting main method in MyOwnProcessor.java");
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("QueueA").processRef("MyOwnProcessor").to("QueueB");
}
};
System.out.println("main is done.");
} //end main
public void process(Exchange exchange) {
System.out.println("Hello the process was executed.");
String s = exchange.getIn().getBody(String.class);
exchange.getIn().setBody("The body of the message is: " + s);
} //end process method
} //end class
Here is the current output:
Starting main method in MyOwnProcessor.java
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
main is done.
Try this,
public static void main(String args[]) throws Exception {
// create CamelContext
CamelContext context = new DefaultCamelContext();
// connect to embedded ActiveMQ JMS broker
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"tcp://localhost:61616");
context.addComponent("jms",
JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
// add our route to the CamelContext
context.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from("jms:queue:QueueA")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String s = exchange.getIn().getBody(String.class);
System.out.println("The body of the message is: " + s);
}
}).to("jms:queue:QueueB");
}
});
// start the route and let it do its work
context.start();
Thread.sleep(10000);
// stop the CamelContext
context.stop();
}
Creating a route isn't going to cause it to run -- you still need a running CamelContext, and it needs to be passed a message in order to get things started. Try getting this to work first, just using an anonymous inner class for your Processor:
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:source").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Success!");
}
});
}
};
context.addRoutes(builder);
ProducerTemplate template = context.createProducerTemplate();
context.start();
template.sendBody("direct:source", "test");
}
Once that works, add a separate class that implements Processor and use that instead of the anonymous inner class.
Keeps running:
package app;
import javafx.application.Application;
import javafx.stage.Stage;
public class Test extends Application {
static {
throwAnException();
}
#Override
public void start(Stage primaryStage) throws Exception {
}
public static void main(String[] args) {
launch(args);
}
private static void throwAnException() {
throw new RuntimeException();
}
}
Stops:
package app;
import javafx.application.Application;
import javafx.stage.Stage;
public class Test extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
}
public static void main(String[] args) {
throwAnException();
launch(args);
}
private static void throwAnException() {
throw new RuntimeException();
}
}
Why?
In the first case the program keeps running, even with the exception.
In the second case the program stops before calling the javafx thread.
The static initializer should run before the main method, right?
My english is vary bad so i didn't write much.
I hope you understand my question.
This is kind of a cheap answer
It keeps running because there are 4(3) other Threads running ..
when you exit/close/shutdown your application through stop() you kill it the right way, also i think, the main Thread is triggered after the stop() method so if you have an exception there, it pretty much happens after the show, if you throw the exception in the init() method the app shutdowns for real - the init() method starts two additional threads..
replace this and see
static {
new Thread(new Runnable() {
#Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("There are "+ Thread.activeCount()+" still running");
}
}
}).start();
throwAnException();
}
package com.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class FirstRoute {
public static void main(String args []) throws Exception{
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:C:\\workspace\\input?noop=true").process(new strong textProcessor() {
#Override
public void process(Exchange arg0) throws Exception {
System.out.println("hello camel!");
}
}).to("file:C:\\workspace\\output").end();
}
});
context.start();
Thread.sleep(1000);
context.stop();
}
}
This is my first camel program. looks like every thing is correct. but the file transfer is not happening.
I added
camel conext 2.12.1 jar
camel core 2.12.1 jar
camel ftp 2.12.1 jar
slf4j api 1.7.6 jar
increase the sleep time to get the result correctly.
That 1000 ms is not enough to copy the files from input directory to output directory.
That sleep time specifies a time limit to copy files from input to output. if you increase sleep time context will copy more files from input to output directory
Usually when Camel is used as a standalone application, you should use Main provided by Camel. I have posted the code from their site :
public class MainExample {
private Main main;
public static void main(String[] args) throws Exception {
MainExample example = new MainExample();
example.boot();
}
public void boot() throws Exception {
// create a Main instance
main = new Main();
// enable hangup support so you can press ctrl + c to terminate the JVM
main.enableHangupSupport();
// bind MyBean into the registery
main.bind("foo", new MyBean());
// add routes
main.addRouteBuilder(new MyRouteBuilder());
// run until you terminate the JVM
System.out.println("Starting Camel. Use ctrl + c to terminate the JVM.\n");
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer:foo?delay=2000")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Invoked timer at " + new Date());
}
})
.beanRef("foo");
}
}
public static class MyBean {
public void callMe() {
System.out.println("MyBean.calleMe method has been called");
}
}
}
Refer http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html for more details.
context.start();
Thread.sleep(10000);
context.stop();
Change this piece of code to give time for camel to move the file.
Your code return some exception?
The problem can be the timeout 1000 is equals 1 second, is a very short time for copy a file, you can try, up the value of timeout or remove.
Follow an example without timeout:
This Class create a RouteBuilder
public class CamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("file:/opt/files-camel?noop=true")
.routeId("file-in")
.choice()
.when(header(Exchange.FILE_NAME).endsWith(".xml"))
.to("file:/opt/files-camel/xml?noop=true")
.when(header(Exchange.FILE_NAME).endsWith(".txt"))
.to("file:/opt/files-camel/txt?noop=true")
.end()
.end();
}
}
This Class run a RouteBuilder
public class Launcher {
public static void main(String... args) throws Exception {
Main main = new Main();
main.addRouteBuilder(new CamelRoute());
main.run(args);
}
}
My application use rmi for serve client request to manipulate data on a database (using JDBC). I would like that skeleton run a thread for each client's operation request. I need just to to something like
public MySkeleton implement MyInterface {
public string method1() {
myThread.start();
}
or something else?
You don't need to do anything special whatsoever, the RMI framework takes care of spinning off new threads automatically for you. Try it with the simplest server possible, you will see that every time a new client connects it is always able to connect to the server straightaway:
public interface Server extends java.rmi.Remote {
void doIt () throws java.rmi.RemoteException;
}
public class ServerImpl extends java.rmi.server.UnicastRemoteObject implements Server {
public ServerImpl() throws java.rmi.RemoteException {
super();
}
public void doIt () {
System.out.println ("Starting in " + Thread.currentThread().getName());
try { Thread.sleep(10000); } catch(InterruptedException t) {}
System.out.println ("Stopping in " + Thread.currentThread().getName());
}
public static void main (String[] argv) throws Exception {
java.rmi.registry.LocateRegistry.createRegistry(1099);
java.rmi.Naming.rebind ("//localhost/Server", new ServerImpl ());
}
}
public class Client {
public static void main(String[] argv) throws Exception {
((Server) java.rmi.Naming.lookup("Server")).doIt();
}
}
I would like that skeleton run a thread for each client's operation request.
RMI already does that.
I need just to to something like
No you don't. Just write the method normally. RMI will multithread it for you.