Shutdown hooks in Spring - java

I am trying to add a shutdown hook via Runtime.getRuntime().addShutdownHook() in a Spring Gradle application.
I tried adding an anonymous thread subclass to the Application.java class from this exact tutorial So that it looks like this:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("Shutdown Thread!");
}
};
Runtime.getRuntime().addShutdownHook(thread);
SpringApplication.run(Application.class, args);
}
}
However, I am not seeing the desired behavior: printing "Shutdown Thread!" on exiting the application. What is going wrong here?
edit: I have been shutting it down using control + c on the terminal where it is running. I am running it on the OSX terminal

Related

Intelij IDEA 2022.1 Cannot debug Runtime.getRuntime().addShutdownHook();

I've tried to debug Runtime.getRuntime().addShutdownHook(unfortunateHook); in sample tapestry application created with Maven quickstart, but it seems that it doesn't work - Debugger doesn't stop at trap set to line set at LOGGER.debug("In the main hook!!!");
Example code:
package org.example.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication
public class App extends SpringBootServletInitializer {
private static final Logger LOGGER= LoggerFactory.getLogger(App.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AppConfiguration.class);
}
public static void main(String[] args) throws Exception {
Thread unfortunateHook = new Thread(() -> {
LOGGER.debug("In the main hook!!!");
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
});
Runtime.getRuntime().addShutdownHook(unfortunateHook);
LOGGER.debug("Simple log statement with inputs {}, {} and {}", 1,2,3);
SpringApplication application = new SpringApplication(App.class);
SpringApplication.run(App.class, args);
}
}
Is it possible to debug code inside shutdown hook thread? I'm using InteliJ Idea 2022.01. Killing application with standard Intelij Idea way (red square).
Ok, after some more digging I have found this: https://youtrack.jetbrains.com/issue/IDEA-170313/Breakpoints-not-working-after-stop-signal and many more simmilar threads.
In short, Idea is disconnecting debugger in a moment that you click red square and sends signal to app to kill itself. Because of these, traps are not working any more.
Workaround to this is to send kill signal from external source. In Linux it's pretty easy but in windows (which is I'm using) you should:
Put a break point any place in your code that will be executed
When code stops at your trap, you go to "evaulate expression" (alt+f8 or from degug acctions) and write System.exit(0)
You breakpoint may need to be set up as a thread one - to do that, click right button on it and switch to "Thread"
Then breakpoint should work.

Spring Boot console application causes JUnit test case to wait

I have Spring Boot console application which accepts user input. In the same application, there are service to perform some logic.
On running the service's JUnit test case directly, I am observing a behavior where the console application stays in the state of accepting user input, and thus not entering the JUnit tests.
Usually there is no issue becasue for a normal Spring Boot application, there is nothing to run on start up. But for this console application setup, it awaits user input.
May I know if there is any way that can make the test cases run while not triggering the console application? Thank you very much.
Observation: The console application is triggered on JUnit test case run, test case is not entered
Main application
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ToyRobotApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ToyRobotApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
// Instruct user to perform input
System.out.println("Welcome to toy robot application!");
System.out.println("Below are the possible operations:");
System.out.println("PLACE <x-coordinate> <y-coordinate> <facing>");
System.out.println("MOVE");
System.out.println("LEFT");
System.out.println("RIGHT");
System.out.println("REPORT");
while (true) {
System.out.println("Please enter your command:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String usrInput = br.readLine();
//...
}
}
}
Test case
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.somecompany.model.Facing;
import com.somecompany.model.Location;
import com.somecompany.model.Robot;
import com.somecompany.service.ToyRobotService;
#SpringBootTest
public class ToyRobotReportTest {
#Autowired
private Robot robot;
#Autowired
private ToyRobotService toyRobotService;
#Test
public void shouldBeAbleToReportLocation() {
Location location = new Location();
location.setXCor("1");
location.setYCor("2");
location.setFacing(Facing.NORTH);
robot.setLocation(location);
// Actual result
String result = toyRobotService.report();
// Assertion
assertEquals("1,2,NORTH", result);
}
}
Note: Other sources omitted
I got the setup working after some research. To get this to work, the JUnit test class should not be annotated with the usual #SpringBootTest annotation.
When the class is annotated with #SpringBootTest, it will start up the application's context (i.e. start the application). In most usual test scenarios, this should be fine if there is no waiting of user input.
In our case, we want the Spring Boot annotations (e.g. #Autowired) to be recognized, but do not want the application itself to be started up.
We can use the following in JUnit:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = ToyRobotApplication.class, initializers = ConfigDataApplicationContextInitializer.class)
public class ToyRobotPlaceTest {
...
}
This will regonize spring annotations, but will not start the application context.

Alternative to setSubscriber in Esper

I am trying to attach a subscriber to an event in Esper but I would like to use .epl file for that. I've been browsing repositories and I have seen examples of doing that by using annotation interfaces. I was trying to do it the same way they do it in CoinTrader, but I can't seem to get it to work. Yet, if I set the subscriber in Java, it works.
This is my project structure for reference
This is my .epl file:
module queries;
import events.*;
import configDemo.*;
import annotations.*;
create schema MyTickEvent as TickEvent;
#Name('allEvents')
#Description('test')
#Subscriber(className='configDemo.TickSubscriber')
select * from TickEvent;
#Name('tickEvent')
#Description('Get a tick event every 3 seconds')
select currentPrice from TickEvent;
This is my config file:
<?xml version="1.0" encoding="UTF-8"?>
<esper-configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.espertech.com/schema/esper"
xsi:noNamespaceSchemaLocation="esper-configuration-6-0.xsd">
<event-type-auto-name package-name="events"/>
<auto-import import-name="annotations.*"/>
<auto-import import-name="events.*"/>
<auto-import import-name="configDemo.*"/>
This is my Subscriber interface:
package annotations;
public #interface Subscriber {
String className();
}
This is my event class:
package configDemo;
import events.TickEvent;
public class TickSubscriber {
public void update(TickEvent tick) {
System.out.println("Event registered by subscriber - Tick is: " +
tick.getCurrentPrice());
}
}
And my main file is this:
package configDemo;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.deploy.DeploymentException;
import com.espertech.esper.client.deploy.DeploymentOptions;
import com.espertech.esper.client.deploy.Module;
import com.espertech.esper.client.deploy.ParseException;
public class Main {
public static EngineHelper engineHelper;
public static Thread engineThread;
public static boolean continuousSimulation = true;
public static void main(String[] args) throws DeploymentException, InterruptedException, IOException, ParseException {
engineHelper = new EngineHelper();
DeploymentOptions options = new DeploymentOptions();
options.setIsolatedServiceProvider("validation"); // we isolate any statements
options.setValidateOnly(true); // validate leaving no started statements
options.setFailFast(false); // do not fail on first error
Module queries = engineHelper.getDeployAdmin().read("queries.epl");
engineHelper.getDeployAdmin().deploy(queries, null);
CountDownLatch latch = new CountDownLatch(1);
EPStatement epl = engineHelper.getAdmin().getStatement("allEvents");
//epl.setSubscriber(new TickSubscriber());
engineThread = new Thread(new EngineThread(latch, continuousSimulation, engineHelper.getRuntime()));
engineThread.start();
}
}
As you can see the setSubscriber line is commented out. When I run it as is, I expected that the subscriber will be recognized and registered and yet it isn't. I only get the tick events flowing in the console. If I decomment the line and I run it, I get a notification after each tick that the subscriber received the event and it all works fine.
What am I doing wrong? How can I set a subscriber within the .epl file?
Assigning a subscriber is done by the application and is not something that the engine does for you. The app code would need to loop thru the statements, get the annotations "stmt.getAnnotations" and inspect these and assign the subscriber.

Spring framework and Quartz scheduler

I have a Spring MVC web application and I want to make use of Quartz scheduler. After reading the docs on Quartz and also on how it integrates with Spring, I am left wondering.
Will Quartz handler run as a separate process independent of tomcat or is it just another maven dependency that I will add be able to schedule within my controllers?.
This is the tutorial that I am reading from https://dzone.com/articles/integrating-quartz-withspring
Quartz is just another maven dependency which starts a daemon thread in the background and keeps looking into QRTZ_CRON_TRIGGERS every defined interval, which stores when the job run last time, and when it is going to run next time. You can get more detailed diagram at http://www.javarticles.com/wp-content/uploads/2016/03/QuartzSchedulerModel.png which will help you understand, how it works internally.
I did it in spring REST service:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.some")
public class ApiApplication {
public static void main(final String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
..............
#Component
public class ScheduledTasks {
#Scheduled(cron = "0 1 0 * * *")
public void expiredPromotionsTask() {
log.debug("expiredPromotionsTask begin");
try {
your code here..
log.debug("expiredPromotionsTask end");
} catch (final Exception e) {
log.error(e, "expiredPromotionsTask failed");
}
}

Boolean wont Update from Object.getBoolean();

Pretty much, I'm trying to write a simple program that lets the user choose a file. Unfortunately, JFileChooser through Swing is a little outdated, so I am trying to use JavaFX FileChooser for this. The goal is to run FileGetter as a thread, transfer the file data to the Main Class, and continue from there.
Main Class:
package application;
import java.io.File;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new FileGetter());
FileGetter fg = new FileGetter();
t1.start();
boolean isReady = false;
while(isReady == false){
isReady = FileGetter.getIsReady();
}
File file = FileGetter.getFile();
System.out.println(file.getAbsolutePath());
...
}
}
FileGetter Class:
package application;
import java.io.File;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class FileGetter extends Application implements Runnable {
static File file;
static boolean isReady = false;
#Override
public void start(Stage primaryStage) {
try {
FileChooser fc = new FileChooser();
while(file == null){
file = fc.showOpenDialog(primaryStage);
}
isReady = true;
Platform.exit();
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
launch();
}
public static boolean getIsReady(){
return isReady;
}
public static File getFile(){
return file;
}
}
Problem is that the value of isReady in the while loop doesn't update to true when the user picked a file (the reason I have it is to prevent the code in Main from continuing with a File set to null).
Any help, alternative suggestions, or explanations as of why this happens is very much appreciated!
The java memory model does not require variable values to be the same in different threads except under specific conditions.
What is happening here is that the FileGetter thread is updating the value in the own memory that is only accessed from this thread, but your main thread doesn't see the updated value, since it only sees the version of the variable stored in it's own memory that is different from the one of the FileGetter thread. Each of the threads has it's own copy of the field in memory, which is perfectly fine according to the java specification.
To fix this, you can simply add the volatile modifier to isReady:
static volatile boolean isReady = false;
which makes sure the updated value will be visible from your main thread.
Furthermore I recommend reducing the number of FileGetter instances you create. In your code 3 instances are created, but only 1 is used.
Thread t1 = new Thread(() -> Application.launch(FileGetter.class));
t1.start();
...
The easiest way to implement this
Instead of trying to drive the horse with the cart, why not just follow the standard JavaFX lifecycle? In other words, make your Main class a subclass of Application, get the file in the start() method, and then proceed (in a background thread) with the rest of the application?
public class Main extends Application {
#Override
public void init() {
// make sure we don't exit when file chooser is closed...
Platform.setImplicitExit(false);
}
#Override
public void start(Stage primaryStage) {
File file = null ;
FileChooser fc = new FileChooser();
while(file == null){
file = fc.showOpenDialog(primaryStage);
}
final File theFile = file ;
new Thread(() -> runApplication(theFile)).start();
}
private void runApplication(File file) {
// run your application here...
}
}
What is wrong with your code
If you really want the Main class to be separate from the JavaFX Application class (which doesn't really make sense: once you have decided to use a JavaFX FileChooser, you have decided you are writing a JavaFX application, so the startup class should be a subclass of Application), then it gets a bit tricky. There are several issues with your code as it stands, some of which are addressed in other answers. The main issue, as shown in Fabian's answer, is that you are referencing FileGetter.isReady from multiple threads without ensuring liveness. This is exactly the issue addressed in Josh Bloch's Effective Java (Item 66 in the 2nd edition).
Another issue with your code is that you won't be able to use the FileGetter more than once (you can't call launch() more than once), which might not be an issue in your code now, but almost certainly will be at some point with this application as development progresses. The problem is that you have mixed two issues: starting the FX toolkit, and retrieving a File from a FileChooser. The first thing must only be done once; the second should be written to be reusable.
And finally your loop
while(isReady == false){
isReady = FileGetter.getIsReady();
}
is very bad practice: it checks the isReady flag as fast as it possibly can. Under some (fairly unusual) circumstances, it could even prevent the FX Application thread from having any resources to run. This should just block until the file is ready.
How to fix without making Main a JavaFX Application
So, again only if you have a really pressing need to do so, I would first create a class that just has the responsibility of starting the FX toolkit. Something like:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
public class FXStarter extends Application {
private static final AtomicBoolean startRequested = new AtomicBoolean(false);
private static final CountDownLatch latch = new CountDownLatch(1);
#Override
public void init() {
Platform.setImplicitExit(false);
}
#Override
public void start(Stage primaryStage) {
latch.countDown();
}
/** Starts the FX toolkit, if not already started via this method,
** and blocks execution until it is running.
**/
public static void startFXIfNeeded() throws InterruptedException {
if (! startRequested.getAndSet(true)) {
new Thread(Application::launch).start();
}
latch.await();
}
}
Now create a class that gets a file for you. This should ensure the FX toolkit is running, using the previous class. This implementation allows you to call getFile() from any thread:
import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javafx.application.Platform;
import javafx.stage.FileChooser;
public class FileGetter {
/**
** Retrieves a file from a JavaFX File chooser. This method can
** be called from any thread, and will block until the user chooses
** a file.
**/
public File getFile() throws InterruptedException {
FXStarter.startFXIfNeeded() ;
if (Platform.isFxApplicationThread()) {
return doGetFile();
} else {
FutureTask<File> task = new FutureTask<File>(this::doGetFile);
Platform.runLater(task);
try {
return task.get();
} catch (ExecutionException exc) {
throw new RuntimeException(exc);
}
}
}
private File doGetFile() {
File file = null ;
FileChooser chooser = new FileChooser() ;
while (file == null) {
file = chooser.showOpenDialog(null) ;
}
return file ;
}
}
and finally your Main is just
import java.io.File;
public class Main {
public static void main(String[] args) throws InterruptedException {
File file = new FileGetter().getFile();
// proceed...
}
}
Again, this is pretty complex; I see no reason not to simply use the standard FX Application lifecycle for this, as in the very first code block in the answer.
In this code
while(isReady == false){
isReady = FileGetter.getIsReady();
}
there is nothing that is going to change the state of FileGetter's isReady to true

Categories

Resources