1. Description of the Application:
What is cron job
A cron job is a scheduled task that runs at specified intervals, often used for repetitive tasks like backups,maintenance, or sending emails..
What is springboot
Spring Boot is a project that is built on the top of the Spring Framework. It provides an easier and faster way to set up, configure, and run both simple and web-based applications.
2. How to write cron expression:
ยท There are 6 Asterisks(******) by default in cron expression as shown below. Further each asterisk has some meaning as they denote a value. These values can be assigned as Second, Minute, Hours, Day, Month, WeekDay respectively in sequence as shown below.
ยท A Cron Expression can accept symbols : * โ , / ?
ยท Comma denotes possible values 0 0 4,6 * * *
Above expression denotes execute given task every day 4:00:00AM and 6:00:00 AM
ยท Dash (-) denotes a range, which means consider all possible values between the range 0 0 4-6 * * *
To illustrate, above expression just denotes โexecute given task every day 4:00:00AM, 5:00:00AM and 6:00:00 AMโ
ยท Asterisk(*) denotes any/every/all value
ยท Forward slash(/) denotes a period of time
ยท Question mark(?) denotes any value, but it is applied only at Day & WeekDay when month value is given.
English names can also be used for the day-of-month and day-of-week fields. Use the first three letters of the particular day or month (case does not matter).
3. Cron expression exercise with examples using springboot schedular:
Examples using pointof time...
ยท Write a cron expression that executes a task everyday at 8 AM
ยท Write a cron expression that executes a task at 9AM and 9PM every day
Examples using pointof time continuedโฆ.
ยท Write a cron expression that executes a task every year on Aug 25th 9AM
ยท How to write a cron expression that executes a task on the hour 9AM to 6PM weekdays.
Examples using period of timeโฆ.
a. Use slash(/) for period of time at all positions except week days.
ยท How to write a cron expression that executes a task for every 15 sec gap
ยท At what time the task will be executed by cron expression : 0 0/30 8-10 * * *
Ans: 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day
ยท At what time the task will be executed by cron expression : 0/20 30/10 10 * * *
Ans: Every Day
Start at โ 10:30:00 AM
Next at โ 10:40:20 AM, 10:50:40 AM
Next โ Next Day at 10:30:00 AM and so onโฆ
.
4. How to Schedule Cron Jobs for email alerts Using Quartz Scheduler in Java springboot?
Create springboot project and then,
Java version 17
Maven version 3.9.8
1. Add dependency:
<<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version> <!-- Use the latest version available -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<version>5.1.3</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
in Alert controller file,set cron time...
String time = "18:02";
String cronexpression = CronUtil.createCronExpressionforalert(time);
log.debug("cronexpression{}",cronexpression);
alertRuleSettings.setConsolidatedAlertReportSchedule(cronexpression);
This will create Cron time
in cron util,we have method for cron expression
public static String createCronExpressionforalert(String time) {
String cronExpression = null;
if (!StringUtils.isEmpty(time)) {
String[] timeParts = time.split(":");
if (timeParts.length == 2) {
String hour = timeParts[0];
String minute = timeParts[1];
// cronExpression = generateCronExpression("0","26/10", hour, "*", "*", "?", "*");
cronExpression = generateCronExpression("0", minute, hour, "*", "*", "?", "*");
}
}
return cronExpression;
}
public static String generateCronExpression(final String seconds, final String minutes, final String hours,
final String dayOfMonth, final String month, final String dayOfWeek, final String year) {
return String.format("%1$s %2$s %3$s %4$s %5$s %6$s %7$s", seconds, minutes, hours, dayOfMonth, month, dayOfWeek, year);
}
}
5. Configuring MySQL database, Quartz Scheduler, and Mail Sender
Letโs configure Quartz Scheduler, MySQL database, and Spring Mail. MySQL database will be used for storing Quartz Jobs, and Spring Mail will be used to send emails.
Open src/main/resources/application.properties file and add the following properties -
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/quartz_demo?useSSL=false
spring.datasource.username = root
spring.datasource.password =
## QuartzProperties
spring.quartz.job-store-type = jdbc
spring.quartz.properties.org.quartz.threadPool.threadCount = 5
Readmore
## MailProperties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=test@gmail.com
spring.mail.password=
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
Youโll need to create a MySQL database named quartz_demo. Also, donโt forget to change the spring.datasource.username and spring.datasource.password properties as per your MySQL installation.
Weโll be using Gmailโs SMTP server for sending emails. Please add your password in the spring.mail.password property. You may also pass this property at runtime as command line argument or set it in the environment variable.
Create Quartz Tables
Quartz is an open source job scheduling framework that can be integrated within Java applications. It has powerful features and provides these features with simple usage and integration
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
commit;
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(190) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
commit;
We should create quartz table manually,
we must run your database schema scripts, as seen one example above. You can find scripts in the below link. Scripts change according to the relational database you have chosen.
After you run the database scripts, Quartz table should be listed like this;

Now, configuration is ready for creating jobs and triggers for scheduled tasks
The main Quartz interfaces are listed below:
Job is an interface to be implemented by the classes that contain the business logic that we wish to have executed
JobDetails defines Job instances and data that are related to it
Trigger describes the schedule of job execution
Scheduler is the main Quartz interface that provides all manipulation and searching operations for jobs and triggers
ยท Scheduling Mail Rest Api
@Path("/ws2/mail")
@POST
@Path("/alert/consolidated")
@Produces(MediaType.APPLICATION_JSON)
public @ResponseBody Response emailConsolidatedAlert(final @Context HttpServletRequest httpRequest,
@NotNull(message = "Invalid amzn account id") @HeaderParam("x-gs-amzn-acc-id") Integer alertId) {
try {
alertService.Consolidatedalert(alertId);
// return Response.status(Status.OK).entity(MAPPER.writeValueAsString("Success")).build();
String responseEntity = MAPPER.writeValueAsString("Success");
Response response = Response.status(Status.OK).entity(responseEntity).build();
log.info("Saved email {}", responseEntity);
log.debug("Saved email {}", responseEntity);
System.out.println("Saved email " + responseEntity);
return response;
} catch (JsonProcessingException e) {
e.printStackTrace();
log.error("error sending consolidated email alert", e);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
}
}
Creating the Alert Request
AlertSchedulerRequest alertRequest = new AlertSchedulerRequest(
gsAccount.getAccountID(), alertRuleSettings.getAmazonAccountId(),
gsAccount.getAwsCustomerID(),
settings.getConsolidatedAlertReportSchedule(),
alertRuleSettings.getId(),
alertRuleSettings.getServiceTag(),
alertRuleSettings.getPercentageTag()
);
try {
alertResourceScheduler.createSchedule(alertRequest);
System.out.println("Consolidated alert report schedule created successfully for account ID: " + gsAccount.getAccountID());
} catch (SchedulerException e) {
log.error("Error scheduling consolidated alert report email request for account " + gsAccount.getAccountID(), e);
}
ยท Schedule Request:
This class is used to encapsulate the details needed to schedule an alert.
Above alertscheduler details encapsulate into below classโฆ.
package com.gs.ci.ciengine.scheduler;
import org.hibernate.validator.constraints.NotEmpty;
public class AlertSchedulerRequest {
@NotEmpty
private Integer gsAccountID;
@NotEmpty
private Integer amznAccountID;
@NotEmpty
private String amznCustomerID;
@NotEmpty
private String cronExpression;
@NotEmpty
private Integer alertId;
@NotEmpty
private String serviveTag;
@NotEmpty
private String percentageTag;
public AlertSchedulerRequest() {
}โฆโฆโฆโฆโฆ
public AlertSchedulerRequest(Integer gsAccountID, Integer amznAccountID,
String amznCustomerID,
String cronExpression,
Integer alertId, String serviveTag, String percentageTag) {
super();
this.gsAccountID = gsAccountID;
this.amznAccountID = amznAccountID;
this.amznCustomerID = amznCustomerID;
this.cronExpression = cronExpression;
this.alertId = alertId;
this.serviveTag = serviveTag;
this.percentageTag = percentageTag;
}
public Integer getGsAccountID() {
return gsAccountID;
}
public void setGsAccountID(Integer gsAccountID) {
this.gsAccountID = gsAccountID;
}
public Integer getAmznAccountID() {
return amznAccountID;
}
public void setAmznAccountID(Integer amznAccountID) {
this.amznAccountID = amznAccountID;
}
public String getAmznCustomerID() {
return amznCustomerID;
}
public void setAmznCustomerID(String amznCustomerID) {
this.amznCustomerID = amznCustomerID;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public Integer getAlertId() {
return alertId;
}
public void setAlertId(Integer alertId) {
this.alertId = alertId;
}
public String getServiveTag() {
return serviveTag;
}
public void setServiveTag(String serviveTag) {
this.serviveTag = serviveTag;
}
public String getPercentageTag() {
return percentageTag;
}
public void setPercentageTag(String percentageTag) {
this.percentageTag = percentageTag;
}
}
ยท Schedular Response
This class is used to encapsulate the response after attempting to schedule an alert. It contains fields like success, jobId, jobGroup, and message.
package com.gs.ci.ciengine.scheduler;
public class AlertSchedulerResponse {
private boolean success;
private String jobId;
private String jobGroup;
private String message;
public AlertSchedulerResponse() {
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getJobId() {
return jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
ยท Define the job
The job to be scheduled should implement the org.quartz.Job interface..
The interface to be implemented by classes that represent a โjobโ in Quartz. It has a single method called execute() where you write the work that needs to be performed by the Job.
@Slf4j
@PropertySources({ @PropertySource("classpath:${env}-application.properties")
})
public class AlertResourcejob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
System.out.println("print");
log.info("Executing Job with key {}",
jobExecutionContext.getJobDetail().getKey());
JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
if (jobDataMap != null) {
Integer alertId = (Integer) jobDataMap.get("alertId");
if (alertId != null) {
postEmailTrigger(alertId);
// alertService.Consolidatedalert(alertId);
}
}
}
To implement Job interface, you need to implement only one execute method that accepts a parameter of JobExecutionContext type. JobExecutionContext contains information about the job instance, trigger, scheduler, and other information about the job execution
ยท Create job and Trigger:
In AlertResourceschedular,
It is time to create job and trigger to schedule. โSchedulerโ interface can be used by just adding โAutowiredโ annotation
@Autowired
private Scheduler scheduler;
Below code sample shows how to create โJobDetailโ object. As you saw earlier, you should store data to โJobDataMapโ and use this map when creating the JobDetail object. AlertResourcejob class which implements โJobโ interface, should be used here. There is also โidentityโ for the job, like primary key for a job and will be used to call the created job. Samples about how to use will be shown in the next tutorial
public AlertSchedulerResponse createSchedule(AlertSchedulerRequest alertRequest)
throws SchedulerException {
boolean newTrigger = false;
JobDetail jobDetail = buildJobDetail(alertRequest);
ScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(alertRequest.getCronExpression())
.withMisfireHandlingInstructionDoNothing();
System.out.println("ScheduleBuilder created with cron expression: " + alertRequest.getCronExpression());
After creating Job, you must create โTriggerโ, in order to define the schedule of the job. As seen in the below sample code, when creating the Trigger object, you can specify when to start for running the job, period and how many times you want to run the job. Like in the Job, there is also identity to specify unique trigger
Trigger trigger = buildJobTrigger(jobDetail, scheduleBuilder, alertRequest);
CronTrigger ctrigger = (CronTrigger) scheduler.getTrigger(trigger.getKey());
if (null == ctrigger) {
newTrigger = true;
System.out.println("New trigger created for job: " + jobDetail.getKey());
} else {
System.out.println("Trigger already exists for job: " + jobDetail.getKey());
}
if (scheduler.getTriggerState(trigger.getKey()) == Trigger.TriggerState.PAUSED) {
scheduler.resumeJob(jobDetail.getKey());
}
if (newTrigger) {
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("New trigger scheduled for job: " + jobDetail.getKey());
} else {
scheduler.rescheduleJob(trigger.getKey(), trigger);
System.out.println("Trigger rescheduled for job: " + jobDetail.getKey());
}
AlertSchedulerResponse response = buildSchedulerResponse(jobDetail,
alertRequest);
return response;
}
Now, you have Job and Trigger objects, and as seen above sample, you schedule by just โscheduler.scheduleJob(job,trigger)โ. After that, job and trigger objects were saved to โQuartz tablesโ, and job will be fired in the scheduled times.
if (newTrigger) {
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("New trigger scheduled for job: " + jobDetail.getKey());
} else {
scheduler.rescheduleJob(trigger.getKey(), trigger);
System.out.println("Trigger rescheduled for job: " + jobDetail.getKey());
}
ยท Sending email:
Pass the data ,
modal.put("variance", variancefordaily);
modal.put("VariancePercent", VariancePercentfordaily);
modal.put("result", result);
modal.put("hostname", ciConsoleURL);
modal.put("currentMonth", DateUtils.getCurrentMonth());
modal.put("serviceTag", trimmedServiceTag);
modal.put("username", amazonAccount.getGsAccountName());
modal.put("name", amazonAccount.getAmazonAccountName());
emailAlertService.emailConsolidatedAlert(modal, alertRuleSettings);
A Map named modal is populated with various values, including variance, VariancePercent, result, etc.
The emailConsolidatedAlert method of emailAlertService is called with modal and alertRuleSettings
ยท Email alert service:
Injects an instance of EmailAlertSender, which handles sending emails
Injects a VelocityEngine instance for template rendering
@Service
@PropertySources({ @PropertySource("classpath:${env}-application.properties")
})
public class EmailAlertServiceImpl implements EmailAlertService {
@Autowired
EmailAlertSender emailalertsender;
@Value("${ci.support.email}")
String adminEmail;
@Autowired
VelocityEngine velocityEngine;
@Override
public void emailConsolidatedAlert(Map<String, Object> modal, AlertRuleSettings alertRuleSettings) {
try {
String mailsubject = "Test Email Subject";
String mailContent = getContentFromTemplate(modal, alertRuleSettings.getServiceTag());
String recipientEmail = alertRuleSettings.getEmailAlert();
System.out.println("recipientEmail: " + recipientEmail);
String[] serviceNames = alertRuleSettings.getServiceName();
if (StringUtils.isNoneEmpty(mailContent) && serviceNames != null) {
// String[] serviceTags = alertRuleSettings.getServiceTag().split(",");
List<String> serviceNamesList = Arrays.asList(serviceNames);
Object serviceTagObj = modal.get("serviceTag");
if (serviceTagObj != null && serviceTagObj instanceof String) {
String serviceTag = ((String) serviceTagObj).trim();
if (serviceNamesList.contains(serviceTag.trim())) {
mailsubject = "Alert servicename Report - Cloud Insider";
double percentageTag = alertRuleSettings.getPercentageForService(serviceTag);
System.out.println("Service tag: " + serviceTag + ", Percentage tag: " + percentageTag);
boolean sendEmail = false;
for (Map.Entry<String, Object> entry : modal.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Double && "result".equals(key)) {
Double resultValue = (Double) value;
if (resultValue >= percentageTag) {
sendEmail = true;
break;
}
}
}
if (sendEmail) {
emailalertsender.sendEmail(recipientEmail, mailsubject, mailContent);
} else {
System.out
.println("-----------------------------------------------------------------------");
System.out.println("Variance value for '" + serviceTag + "' is less than 10...");
System.out
.println("-----------------------------------------------------------------------");
}
} else {
System.out.println("servicenamelist has no servicetag");
}
} else {
System.out.println("serviceTagObj is null");
}
} else {
System.out.println("Mail content is empty or service names array is null");
}
// Send the email
} catch (Exception e) {
e.printStackTrace(); // Handle exception appropriately
}
}
private String getContentFromTemplate(Map<String, Object> model, String servicetype) {
StringWriter mergedContent = new StringWriter();
VelocityContext velocityContext = new VelocityContext();
String template = null;
if (servicetype != null) {
template = "templates/EC2 others-report.vm";
} else {
System.out.println("it is not ec2-other");
}
for (Map.Entry<String, Object> entry : model.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
velocityContext.put(key, value);
}
velocityContext.put("date", new DateTool());
velocityContext.put("number", new NumberTool());
velocityEngine.mergeTemplate(template, "UTF-8", velocityContext, mergedContent);
return mergedContent.toString();
}
}
This method generates an email alert based on conditions and template content:
Retrieves email content from a Velocity template using getContentFromTemplate.
Checks conditions based on service tag and result value to decide whether to send the email using emailalertsender.sendEmail.
Handles various cases with print statements if conditions are not met..
This method retrieves the content of an email template using Apache Velocity:
โข Determines the template file based on servicetype.
โข Populates Velocity context with data from model.
โข Merges data into the template using velocityEngine.mergeTemplate
ยท Email alert sender:
This method constructs and sends an email using email-builder-lib:
Constructs an Email object using EmailBuilder.
Sends the email using MailerBuilder with SMTP server details.
package com.gs.ci.ciengine.alertmail;
import org.simplejavamail.email.Email;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.email.EmailPopulatingBuilder;
import org.simplejavamail.mailer.MailerBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.stereotype.Service;
@Service
@PropertySources({ @PropertySource("classpath:${env}-application.properties")
})
public class EmailAlertSender {
@Value("${smtp.host}")
String smtpHost;
@Value("${smtp.port}")
String smtpPort;
@Value("${smtp.user}")
String smtpUser;
@Value("${smtp.password}")
String smtpPasswd;
@Value("${smtp.from.name}")
String smtpFromName;
@Value("${smtp.from.email}")
String smtpFromEmail;
@Value("${ci.support.email}")
String adminEmail;
public boolean sendEmail(String tolist, String subject, String body) {
// log.trace("Sending email to " + tolist);
// log.trace("Email body = " + body);
String[] to = tolist.split(",");
if (to.length > 0) {
EmailPopulatingBuilder emailPopulatingBuilder = EmailBuilder.startingBlank()
.from(smtpFromName, smtpFromEmail).withSubject(subject).withHTMLText(body);
for (int i = 0; i < to.length; i++) {
emailPopulatingBuilder.to(to[i]);
}
Email email = emailPopulatingBuilder.buildEmail();
System.out.println("Printing Email Content:");
System.out.println("From: " + email.getFromRecipient());
System.out.println("To: " + email.getRecipients());
System.out.println("Subject: " + email.getSubject());
System.out.println("Body:\n" + email.getPlainText());
MailerBuilder.withSMTPServer(smtpHost, Integer.parseInt(smtpPort), smtpUser,
smtpPasswd).buildMailer()
.sendMail(email, true);
return true;
}
return false;}
}
Open postman check mail api,
This is the api http://localhost:8085/ws2/mail/alert/consolidated

Mail successfully sentโฆ
