OwnCron-A lightweight Java Tool ...Leverage Scheduling your Java Business logic an out-of-the-box way
Scheduling is an important and commonplace requirement in Enterprise applications. Scheduled Jobs, aka CRONS are achieved differently across different environments, Operating Systems and Technology Stacks. Some of such technologies include, Linux’s very-own crontab , Windows schtasks.
Java supports multiple approaches to schedule jobs , ranging from Java’s vanilla package supports like java.util.TimerTask , java.util.concurrent.ScheduledExecutorService to well-established frameworks like Quartz , Spring Schedulers etc. While these frameworks have been out for years and maintained by respective communities, they seek to be integrated within the codebase itself.
Leverage Scheduling Out-of-the-Box & independent of OS
crontab is a popular utility to schedule tasks in Linux environment , and widely used in server systems. With all these pieces of resources sufficing to meet our needs, I once came across a USE-CASE , where scheduling had to be carried out irrespective of environments plus, the Business Logic had been written in Java and re-shaping them to native shell scripts would have been a costly reinvention with little luxury left for affordability!
Picking pebbles up and placing them in order, from this use-case, I created this small utility to cater to similar requirement. OwnCron- aims to make scheduling available in an out-of-the-box manner. The business logic remains inside one or multiple methods of a fully isolated Java class.
Beginner’s Manual
[A] Setting Things up:
- Ensure you've Java SE 8 or above on your system.
In case you don't please follow Java 8 installation guide
[B] Getting Started:
Please follow these steps:
- Let us say, you have N (E.g. 3) business logic components to schedule. Write these pieces of logic components in N independent methods inside a class [Listing-1]
import java.util.Date; public class MyGoodClass{ void s1(){ System.out.println("I am a Dummy logic "); } /*Another method*/ String s2() throws Exception /*this isn't rule. Left to implementation of handling Checked Exceptions */{ System.out.println("I am another Dummy logic "); Thread.sleep(10000L); // This is to show thread-safety. You don't need it System.out.println("I executed at"+new Date()); return Thread.currentThread().getName(); // Whatever your logic returns } /*yet Another method*/ String s3() throws Exception{ System.out.println("I am another logic"); Thread.sleep(10000L); System.out.println("Hi there! I executed at "+new Date()); return Thread.currentThread().getName(); } } }
[Listing-1]
2. Create an annotation as shown below:
import java.lang.reflect.*; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) /*You can assign any name to this annotation*/ public @interface IA1{ public String value(); /* Just ensure it has a mandatory attribute "value"*/ }
[Listing -2]
Note: You can assign any name to this annotation. Just ensure it has the mandatory attribute "value"
3. Annotate the class in [Listing-1] with the annotation you created in [Listing -2], passing a valid , Spring CRON expression in its "value" attribute.
Example- to schedule a method to execute daily at 16:40:00 (Local time-zone) annotate the corresponding method as @IA1("0 40 16 * * ?") .
The complete listing looks like:
import java.util.Date; public class MyGoodClass{ @IA1("0 40 16 * * ?") // Schdule at 16:40 void s1(){ System.out.println("I am a Dummy logic "); } /*Another method*/ // Scheduled at 18:21 regualrly @IA1("0 21 18 * * ?") String s2() throws Exception /*this isn't rule. Left to implementation of handling Checked Exceptions */{ System.out.println("I am another Dummy logic "); Thread.sleep(10000L); // This is to show thread-safety. You don't need it System.out.println("I executed at"+new Date()); return Thread.currentThread().getName(); // Whatever your logic returns } /*yet Another method*/ // Schduled at 14:10 on 15th of each month @IA1("0 10 14 15 * ?") String s3() throws Exception{ System.out.println("I am another logic"); Thread.sleep(10000L); System.out.println("Hi there! I executed at "+new Date()); return Thread.currentThread().getName(); } } }
4. You're almost Done! Final step:
In command line, use this utility as shown, passing three VM arguments:
- app.class.name= The class that holds all these business methods
- app.class.dir= Path to the folder on local disk, where this class is stored
- app.annotation.class.name=Name of the Annotation class [Listing -2]
java -Dapp.class.dir=D:/abc -Dapp.class.name=MyGoodClass -Dapp.annotation.class.name=IA1 -jar EasyCron-0.0.1-SNAPSHOT.jar
It may be noted that the methods can be scheduled independently .
Also, the business developers, who write these methods , need not worry about the name of Annotation and thus, is left with no additional API dependencies.
Conclusion:
- As of current release, this does not yet support multiple Java classes. This feature will be there in some later release.
- Though business development is spared with the concern of depending on a third party annotation, it's worth noting that the annotation, whatever it is, is required to have a mandatory attribute , "value". This needs to change to an lesser common name.
- The simple illustration shown here, is less realistic, as business logic will usually span across multiple java classes and involve classpath dependencies. This, however, loads classes from a work space, too ; and not just from a single .class file on the disk. Loading necessary classes from JAR files and classpath dependencies, is supported , as well
Please try this yourself... estimated time is 5 -7 minutes only!
Happy Coding !
Renewable Energy Professional | Business Development - Solar Modules , Inverters , Storage Systems
4yGreat Soham