com.lucidchart.piezo.admin.controllers.TriggerFormHelper.scala Maven / Gradle / Ivy
The newest version!
package com.lucidchart.piezo.admin.controllers
import com.lucidchart.piezo.TriggerMonitoringPriority
import com.lucidchart.piezo.TriggerMonitoringPriority.TriggerMonitoringPriority
import com.lucidchart.piezo.admin.utils.CronHelper
import java.text.ParseException
import org.quartz._
import play.api.data.{Form, FormError}
import play.api.data.Forms._
import play.api.data.format.Formats.parsing
import play.api.data.format.Formatter
import play.api.data.validation.{Constraint, Constraints, Invalid, Valid, ValidationError}
class TriggerFormHelper(scheduler: Scheduler) extends JobDataHelper {
private def simpleScheduleFormApply(repeatCount: Int, repeatInterval: Int): SimpleScheduleBuilder = {
SimpleScheduleBuilder
.simpleSchedule()
.withRepeatCount(repeatCount)
.withIntervalInSeconds(repeatInterval)
}
private def simpleScheduleFormUnapply(simple: SimpleScheduleBuilder) = {
val simpleTrigger = simple.build().asInstanceOf[SimpleTrigger]
Some((simpleTrigger.getRepeatCount, simpleTrigger.getRepeatInterval.toInt / 1000))
}
private def cronScheduleFormApply(cronExpression: String): CronScheduleBuilder = {
CronScheduleBuilder.cronSchedule(cronExpression)
}
private def cronScheduleFormUnapply(cron: CronScheduleBuilder) = {
val cronTrigger = cron.build().asInstanceOf[CronTrigger]
Some((cronTrigger.getCronExpression()))
}
private def triggerFormApply(
triggerType: String,
group: String,
name: String,
jobGroup: String,
jobName: String,
description: String,
simple: Option[SimpleScheduleBuilder],
cron: Option[CronScheduleBuilder],
jobDataMap: Option[JobDataMap],
triggerMonitoringPriority: String,
triggerMaxErrorTime: Int,
triggerMonitoringTeam: Option[String],
): (Trigger, TriggerMonitoringPriority, Int, Option[String]) = {
val newTrigger: Trigger = TriggerBuilder
.newTrigger()
.withIdentity(name, group)
.withDescription(description)
.withSchedule(triggerType match {
case "cron" => cron.get
case "simple" => simple.get
})
.forJob(jobName, jobGroup)
.usingJobData(jobDataMap.getOrElse(new JobDataMap()))
.build()
(
newTrigger,
TriggerMonitoringPriority.withName(triggerMonitoringPriority),
triggerMaxErrorTime,
triggerMonitoringTeam,
)
}
private def triggerFormUnapply(tp: (Trigger, TriggerMonitoringPriority, Int, Option[String])): Option[
(
String,
String,
String,
String,
String,
String,
Option[SimpleScheduleBuilder],
Option[CronScheduleBuilder],
Option[JobDataMap],
String,
Int,
Option[String],
),
] = {
val trigger = tp._1
val (triggerType: String, simple, cron) = trigger match {
case cron: CronTrigger => ("cron", None, Some(cron.getScheduleBuilder))
case simple: SimpleTrigger => ("simple", Some(simple.getScheduleBuilder), None)
}
val description = if (trigger.getDescription() == null) "" else trigger.getDescription()
Some(
(
triggerType,
trigger.getKey.getGroup(),
trigger.getKey.getName(),
trigger.getJobKey.getGroup(),
trigger.getJobKey.getName(),
description,
simple.asInstanceOf[Option[SimpleScheduleBuilder]],
cron.asInstanceOf[Option[CronScheduleBuilder]],
Some(trigger.getJobDataMap),
tp._2.toString,
tp._3,
tp._4,
),
)
}
private def getCronParseError(cronExpression: String): String = {
try {
new CronExpression(cronExpression).getCronExpression()
} catch {
case e: ParseException => e.getMessage()
}
}
def isValidCronExpression(cronExpression: String): Boolean = {
try {
new CronExpression(cronExpression)
true
} catch {
case e: ParseException => false
}
}
def validCronExpression: Constraint[String] = Constraint[String]("Invalid cron expression") { cronExpression =>
if (!isValidCronExpression(cronExpression)) {
Invalid(ValidationError(getCronParseError(cronExpression)))
} else {
Valid
}
}
def buildTriggerForm: Form[(Trigger, TriggerMonitoringPriority, Int, Option[String])] = Form(
mapping(
"triggerType" -> nonEmptyText(),
"group" -> nonEmptyText(),
"name" -> nonEmptyText(),
"jobGroup" -> nonEmptyText(),
"jobName" -> nonEmptyText(),
"description" -> text(),
"simple" -> optional(
mapping(
"repeatCount" -> number(),
"repeatInterval" -> number(),
)(simpleScheduleFormApply)(simpleScheduleFormUnapply),
),
"cron" -> optional(
mapping(
"cronExpression" -> nonEmptyText().verifying(validCronExpression),
)(cronScheduleFormApply)(cronScheduleFormUnapply),
),
"job-data-map" -> jobDataMap,
"triggerMonitoringPriority" -> nonEmptyText(),
"triggerMaxErrorTime" -> of(MaxSecondsBetweenSuccessesFormatter).verifying(Constraints.min(0)),
"triggerMonitoringTeam" -> optional(text()),
)(triggerFormApply)(triggerFormUnapply)
.verifying(
"Job does not exist",
fields => {
scheduler.checkExists(fields._1.getJobKey)
},
),
)
}
object MaxSecondsBetweenSuccessesFormatter extends Formatter[Int] {
override val format = Some(("format.triggerMaxErrorTime", Nil))
override def bind(key: String, data: Map[String, String]): Either[Seq[FormError], Int] = {
for {
maxSecondsBetweenSuccesses <- parsing(_.toInt, "Numeric value expected", Nil)(key, data)
maxIntervalTime <- {
if (data.contains("cron.cronExpression")) {
parsing(expr => CronHelper.getMaxInterval(expr), "try again.", Nil)(
"cron.cronExpression",
data,
)
} else {
parsing(_.toLong, "try again.", Nil)("simple.repeatInterval", data)
}
}
_ <- Either.cond(
maxSecondsBetweenSuccesses > maxIntervalTime,
maxSecondsBetweenSuccesses,
List(
FormError(
"triggerMaxErrorTime",
s"Must be greater than the maximum trigger interval ($maxIntervalTime seconds)",
),
),
)
} yield maxSecondsBetweenSuccesses
}
override def unbind(key: String, value: Int) = Map(key -> value.toString)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy