How to enable the scheduler in spring boot based on the static variable at runtime? - spring-boot

Here are the details,
I have two schedulers with #scheduled Annotation. Let's says A & B. "A" Scheduler does some job and set value in static variable using setter. I want to enable the "B" Scheduler only the static variable is set to true.
One solution, I know is to the check/validate the static variable flag in "B" scheduler and skip the further process but the scheduler checks every time based on interval specified (i.e., fixed delay).
I want to completely disable the scheduler based on static variable at run time value.
PS : I manually set the time delay between the "A" & "B" Schedulers. So "A" runs first then "B"
For Example:
Initialize.class
Configuration
EnableScheduling
public class Initialize {
public A a{
return new A();
}
public B b{
return new B();
}
}
A.class
public class A{
Scheduled(fixedDelayString = "sometime specified")
public void aProcessor(){
// Following code sets the value of static variable like staticClass.setAppVariable(true);
}
}
B.class
public class B{
Scheduled(fixedDelayString = "sometime specified")
public void bProcessor(){
// some process
}
}
static.class
public class staticClass implements Serializable{
private static volatile boolean appVariable = false;
public static boolean getAppVariable() {
return appVariable;
}
public static void setAppVariable(boolean appVariable) {
staticClass.appVariable = appVariable;
}
}
But I need to initialise the "B" class/scheduler based on the static variable if it is true.
Any help?

Related

How to use #ConfigProperties with a Converter class

I tried to implement a custom config type and it worked. However, when I use the custom type with a group of config using the #ConfigProperties it fails to automatically recognize the property by its name and instead treats the property as an object with a nested property.
How can I implement such a behavior correctly? (I am new to Quarkus, so please correct me if I am doing something wrong here)
Here is a code snippet that converts a custom type:
public class Percentage {
private double percentage;
public Percentage() {}
public Percentage(double percentage) {
this.percentage = percentage;
}
public void setPercentage(double percentage) {
this.percentage = percentage;
}
public double getPercentage() {
return this.percentage;
}
}
#Priority(300)
public class PercentageConverter implements Converter<Percentage> {
#Override
public Percentage convert(String value) {
int percentIndex = value.indexOf("%");
return new Percentage(Double.parseDouble(value.substring(0, percentIndex - 1)));
}
}
/// this works ------
public class Hello {
#ConfigProperty(name = "custom.vat")
Percentage vat;
public Hello () {
}
// .....
}
/// however, this fails
#ConfigProperties(prefix = "custom")
public class CustomConfig {
public Percentage vat;
public Percentage profit;
}
javax.enterprise.inject.spi.DeploymentException: No config value of type [double] exists for: custom.vat.percentage
at io.quarkus.arc.runtime.ConfigRecorder.validateConfigProperties(ConfigRecorder.java:39)
Unfortunately, I believe this does not work because Quarkus #ConfigProperties, handles these cases as if they were subgroups and try to map nested properties with the configuration (and not use the Converter).
Feel free to open up an issue in Quarkus GH if you feel this should change: https://github.com/quarkusio/quarkus/issues
Alternately, you can use SR Config #ConfigMapping: https://smallrye.io/docs/smallrye-config/mapping/mapping.html. It covers a few more cases, including direct Conversion and in the future it may replace Quarkus #ConfigProperties.

Setting order of injection values from properties in Spring Boot for #Value

I have a question, about setting order for injection the #Value annotation. I tried with #Order, but for this case, that doesn't work.
Why do I ask about that? Because some values are dependent on the others. I can make more logic in #PostConstructor, but if exists any solution for control of order it will be helpful for me.
To clarify, an example that not works:
#Value("${first}")
#Order(1)
public void setFirst(boolean first) {
FIRST = first;
}
#Value("${second}")
#Order(2)
public void setSecond(String second) {
SECOND = second;
if(first){
//do something
}
}
You might use Environment class in order to get a value if something is valid. For example:
#Autowired
private Environment env;
#Value("${first}")
public void setFirst(boolean first) {
FIRST = first;
if (FIRST)
SECOND = env.getProperty("second");
}
It seems that you have two global variables such as
private boolean FIRST;
private String SECOND;
Then you can achieve this as follows:
#Value("${first}")
public void setFirst(boolean first) {
FIRST = first;
}
#Value("${second}")
public void setSecond(String second) {
SECOND = second;
if(FIRST){
//do something
}
}

how to make annotation attribute configuated in application.yml

I want to configuration internal in the application.yml. but it says atrribute value must be constant. What can I do with this situation?
#Value("${robot.internal}")
String internal;
#Scheduled(fixedRate = internal)
public void runAllCheckPoint() {
}
In java Annotations can have only constants expression. Because they are processed at compile time. Annotations are metadata (for class, interface, variables, methods or annotations itself), which should not change on run time.
Valid Usage
#Scheduled(fixedRate = "10")
public void runAllCheckPoint() {
}
private static final String FIXED_RATE = "10";
#Scheduled(fixedRate = FIXED_RATE)
public void runAllCheckPoint() {
}

What does ContainingType mean in java method reference

In Java Method References
ContainingClass::staticMethodName - means that a class can refer the static method (Reference to a Static Method )
containingObject::instanceMethodName - means that a class object is created first and then that object is used to refer the instanceMethod .
My doubt is
ContainingType::methodName - what does the ContainingType mean ?
Is ContainingType a predefined class in java like String or something else ?
Java Language Specification, §4.3. Reference Types and Values:
There are four kinds of reference types: class types (§8.1), interface types (§9.1), type variables (§4.4), and array types (§10.1).
Array type don't have static methods, so that doesn't apply to static method reference, but you can do the other 3:
class MyClass {
static void doIt() {/*doing it*/}
}
interface MyInterface {
static void doIt() {/*doing it*/}
}
class Test<T extends MyClass> {
void test() {
Runnable m1 = MyClass::doIt; // class type
Runnable m2 = MyInterface::doIt; // interface type
Runnable m3 = T::doIt; // type variable
}
}
Now that link is provided in a comment, it says:
Reference to a static method
ContainingClass::staticMethodName
Reference to an instance method of a particular object
containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type
ContainingType::methodName
Reference to a constructor
ClassName::new
Here, again, ContainingType refers to any of the 3 reference types mentioned above: Class, Interface, and Type Variable.
You can then make a method reference for any instance method of such a type.
class MyClass {
void doIt() {/*doing it*/}
}
interface MyInterface {
void doIt();
}
class Test<T extends MyClass> {
void test() {
Consumer<MyClass> m1 = MyClass::doIt;
Consumer<MyInterface> m2 = MyInterface::doIt;
Consumer<T> m3 = T::doIt;
}
}
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
In the document you gave,there is a example of the ContainingType:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
and explains:
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
I think,the element of the stringArray dosen't have a name (eg: String s1 = "Barbara"),so you can't refer it by containingObject::instanceMethodName(eg:s1::compareToIgnoreCase). That's why it uses ContainingType.
I think your ContainingType::methodName is a general/common form of the 2 forms above...
Think about the below code. You can replace the <methodReference> width
InterfaceA::method (for ContainingType::methodName)
ClassA::method (for also ContainingType::methodName)
ClassB::instanceMethod (for ContainingObject::instanceMethodName) or
ClassB::staticMethod (for ContainingClass::staticMethodName)
to demonstrate the mentioned cases:
public class App {
interface InterfaceA {
String method();
}
static class ClassA implements InterfaceA {
public String method() {
return "ContainingType::methodName";
}
}
static class ClassB extends ClassA {
public String instanceMethod() {
return "ContainingObject::instanceMethodName";
}
public static String staticMethod(ClassB classB) {
return "ContainingClass::staticMethodName";
}
}
public static void main(String[] args) {
System.out.println(((Function<ClassB, String>) <methodReference>).apply(new ClassB()));
}
}

Set the cron expression value dynamically

I want to set the cron expression value dynamically using controller. This is my code snippet.
#Service
#EnableScheduling
#Configuration
#PropertySources({
#PropertySource("classpath:properties/cron.properties")
})
public class SchedulerServiceImpl implements SchedulerService{
private final static Logger log = LoggerFactory.getLogger(SchedulerServiceImpl.class);
#Value( "${cron.expression}")
private String cronValue;
#Scheduled(cron = "${cron.expression}")
public void getTweetsFromAPI(){
log.info("Trying to make request for get Tweets through TweetController.");
log.debug("----------------Executing cron.expression {}----------------",cronValue);
}
}
how can I set the cron.expression value dynamically after the deployment. If I used a controller and replace the properties file existing value, Does it work?
Logically your question is wrong. Cron expression is for scheduling a method for a specified time i.e. the method will be executed at a specified time say 12 noon everyday.
Now if you are dynamically changing the cron expression value that means you are controlling the execution of this method and not the scheduler which is wrong.
You can do something like below:-
#Value( "${cron.expression1}")
private String cron1;
#Value( "${cron.expression2}")
private String cron2;
#Scheduled(cron=cron1)
public void method1(){
//call to method
this.method();
}
#Scheduled(cron=cron2)
public void method2(){
//call to method
this.method();
}
private void method(){
//Your scheduling logic goes here
}
Here you are reusing the method() to be scheduled at two different times.

Resources