diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/quartz.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/quartz.adoc
new file mode 100644
index 000000000000..8a6ffc56006f
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/quartz.adoc
@@ -0,0 +1,45 @@
+[[quartz]]
+= Quartz (`quartz`)
+
+The `quartz` endpoint provides information about the scheduled jobs that are managed by
+Quartz Scheduler.
+
+
+
+[[quartz-report]]
+== Retrieving the Quartz report
+
+To retrieve the Quartz, make a `GET` request to `/application/quartz`,
+as shown in the following curl-based example:
+
+include::{snippets}quartz-report/curl-request.adoc[]
+
+The resulting response is similar to the following:
+
+include::{snippets}quartz-report/http-response.adoc[]
+
+
+
+[[quartz-job]]
+== Retrieving the Quartz job details
+
+To retrieve the Quartz, make a `GET` request to `/application/quartz/{group}/{name}`,
+as shown in the following curl-based example:
+
+include::{snippets}quartz-job/curl-request.adoc[]
+
+The preceding example retrieves the job with the `group` of `groupOne` and `name` of
+`jobOne`. The resulting response is similar to the following:
+
+include::{snippets}quartz-job/http-response.adoc[]
+
+
+
+[[quartz-job-response-structure]]
+=== Response Structure
+
+The response contains details of the scheduled job. The following table describes the
+structure of the response:
+
+[cols="2,1,3"]
+include::{snippets}quartz-job/response-fields.adoc[]
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
index e30d7e6616c5..17c03ab0e828 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc
@@ -63,6 +63,7 @@ include::endpoints/logfile.adoc[leveloffset=+1]
include::endpoints/loggers.adoc[leveloffset=+1]
include::endpoints/metrics.adoc[leveloffset=+1]
include::endpoints/prometheus.adoc[leveloffset=+1]
+include::endpoints/quartz.adoc[leveloffset=+1]
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
include::endpoints/sessions.adoc[leveloffset=+1]
include::endpoints/shutdown.adoc[leveloffset=+1]
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfiguration.java
new file mode 100644
index 000000000000..6f8a4342fb7e
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.quartz;
+
+import org.quartz.Scheduler;
+
+import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.quartz.QuartzEndpoint;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for {@link QuartzEndpoint}.
+ *
+ * @author Vedran Pavic
+ * @since 2.0.0
+ */
+@Configuration
+@ConditionalOnClass(Scheduler.class)
+@AutoConfigureAfter(QuartzAutoConfiguration.class)
+public class QuartzEndpointAutoConfiguration {
+
+ @Bean
+ @ConditionalOnBean(Scheduler.class)
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ public QuartzEndpoint quartzEndpoint(Scheduler scheduler) {
+ return new QuartzEndpoint(scheduler);
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/package-info.java
new file mode 100644
index 000000000000..27b1939c5f51
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/quartz/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Auto-configuration for actuator Quartz Scheduler concerns.
+ */
+package org.springframework.boot.actuate.autoconfigure.quartz;
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
index 6b24efad9be5..300a6659acba 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -32,6 +32,7 @@ org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAuto
org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\
+org.springframework.boot.actuate.autoconfigure.quartz.QuartzEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/QuartzEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/QuartzEndpointDocumentationTests.java
new file mode 100644
index 000000000000..1dd41a39b922
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/QuartzEndpointDocumentationTests.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SimpleScheduleBuilder;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+import org.quartz.impl.matchers.GroupMatcher;
+
+import org.springframework.boot.actuate.quartz.QuartzEndpoint;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import static org.mockito.BDDMockito.given;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
+import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
+import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
+import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * Tests for generating documentation describing the {@link QuartzEndpoint}.
+ *
+ * @author Vedran Pavic
+ */
+public class QuartzEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
+
+ private static final JobDetail jobOne = JobBuilder.newJob(Job.class)
+ .withIdentity("jobOne", "groupOne").withDescription("My first job").build();
+
+ private static final JobDetail jobTwo = JobBuilder.newJob(Job.class)
+ .withIdentity("jobTwo", "groupOne").build();
+
+ private static final JobDetail jobThree = JobBuilder.newJob(Job.class)
+ .withIdentity("jobThree", "groupTwo").build();
+
+ private static final Trigger triggerOne = TriggerBuilder.newTrigger().forJob(jobOne)
+ .withIdentity("triggerOne").withDescription("My first trigger")
+ .modifiedByCalendar("myCalendar")
+ .startAt(Date.from(Instant.parse("2017-12-01T12:00:00Z")))
+ .endAt(Date.from(Instant.parse("2017-12-01T12:30:00Z")))
+ .withSchedule(SimpleScheduleBuilder.repeatMinutelyForever()).build();
+
+ private static final Trigger triggerTwo = TriggerBuilder.newTrigger().forJob(jobOne)
+ .withIdentity("triggerTwo").withDescription("My second trigger")
+ .modifiedByCalendar("myCalendar")
+ .startAt(Date.from(Instant.parse("2017-12-01T00:00:00Z")))
+ .endAt(Date.from(Instant.parse("2017-12-10T00:00:00Z")))
+ .withSchedule(SimpleScheduleBuilder.repeatHourlyForever()).build();
+
+ @MockBean
+ private Scheduler scheduler;
+
+ @Test
+ public void quartzReport() throws Exception {
+ String groupOne = jobOne.getKey().getGroup();
+ String groupTwo = jobThree.getKey().getGroup();
+ given(this.scheduler.getJobGroupNames())
+ .willReturn(Arrays.asList(groupOne, groupTwo));
+ given(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupOne)))
+ .willReturn(
+ new HashSet<>(Arrays.asList(jobOne.getKey(), jobTwo.getKey())));
+ given(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupTwo)))
+ .willReturn(Collections.singleton(jobThree.getKey()));
+ this.mockMvc.perform(get("/application/quartz")).andExpect(status().isOk())
+ .andDo(document("quartz/report"));
+ }
+
+ @Test
+ public void quartzJob() throws Exception {
+ JobKey jobKey = jobOne.getKey();
+ given(this.scheduler.getJobDetail(jobKey)).willReturn(jobOne);
+ given(this.scheduler.getTriggersOfJob(jobKey))
+ .willAnswer(invocation -> Arrays.asList(triggerOne, triggerTwo));
+ this.mockMvc.perform(get("/application/quartz/groupOne/jobOne"))
+ .andExpect(status().isOk())
+ .andDo(document("quartz/job",
+ preprocessResponse(replacePattern(
+ Pattern.compile("org.quartz.Job"), "com.example.MyJob")),
+ responseFields(
+ fieldWithPath("jobGroup").description("Job group."),
+ fieldWithPath("jobName").description("Job name."),
+ fieldWithPath("description")
+ .description("Job description, if any."),
+ fieldWithPath("className").description("Job class."),
+ fieldWithPath("triggers.[].triggerGroup")
+ .description("Trigger group."),
+ fieldWithPath("triggers.[].triggerName")
+ .description("Trigger name."),
+ fieldWithPath("triggers.[].description")
+ .description("Trigger description, if any."),
+ fieldWithPath("triggers.[].calendarName")
+ .description("Trigger's calendar name, if any."),
+ fieldWithPath("triggers.[].startTime")
+ .description("Trigger's start time."),
+ fieldWithPath("triggers.[].endTime")
+ .description("Trigger's end time."),
+ fieldWithPath("triggers.[].nextFireTime")
+ .description("Trigger's next fire time."),
+ fieldWithPath("triggers.[].previousFireTime").description(
+ "Trigger's previous fire time, if any."),
+ fieldWithPath("triggers.[].finalFireTime").description(
+ "Trigger's final fire time, if any."))));
+ }
+
+ @Configuration
+ @Import(BaseDocumentationConfiguration.class)
+ static class TestConfiguration {
+
+ @Bean
+ public QuartzEndpoint endpoint(Scheduler scheduler) {
+ return new QuartzEndpoint(scheduler);
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfigurationTests.java
new file mode 100644
index 000000000000..1d1c5411257b
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/quartz/QuartzEndpointAutoConfigurationTests.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.autoconfigure.quartz;
+
+import org.junit.Test;
+import org.quartz.Scheduler;
+
+import org.springframework.boot.actuate.quartz.QuartzEndpoint;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link QuartzEndpointAutoConfiguration}.
+ *
+ * @author Vedran Pavic
+ */
+public class QuartzEndpointAutoConfigurationTests {
+
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(
+ AutoConfigurations.of(QuartzEndpointAutoConfiguration.class))
+ .withUserConfiguration(QuartzConfiguration.class);
+
+ @Test
+ public void runShouldHaveEndpointBean() {
+ this.contextRunner.run(
+ (context) -> assertThat(context).hasSingleBean(QuartzEndpoint.class));
+ }
+
+ @Test
+ public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
+ throws Exception {
+ this.contextRunner.withPropertyValues("management.endpoint.quartz.enabled:false")
+ .run((context) -> assertThat(context)
+ .doesNotHaveBean(QuartzEndpoint.class));
+ }
+
+ @Configuration
+ static class QuartzConfiguration {
+
+ @Bean
+ public Scheduler scheduler() {
+ return mock(Scheduler.class);
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/pom.xml b/spring-boot-project/spring-boot-actuator/pom.xml
index 2d08eefbb8e8..0b37678d0500 100644
--- a/spring-boot-project/spring-boot-actuator/pom.xml
+++ b/spring-boot-project/spring-boot-actuator/pom.xml
@@ -106,6 +106,10 @@
liquibase-core
true
+
+ org.quartz-scheduler
+ quartz
+
org.springframework
spring-jdbc
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpoint.java
new file mode 100644
index 000000000000..7aacf17da9e0
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/QuartzEndpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.quartz;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.quartz.Job;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.impl.matchers.GroupMatcher;
+
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.boot.actuate.endpoint.annotation.Selector;
+import org.springframework.util.Assert;
+
+/**
+ * {@link Endpoint} to expose Quartz Scheduler info.
+ *
+ * @author Vedran Pavic
+ * @since 2.0.0
+ */
+@Endpoint(id = "quartz")
+public class QuartzEndpoint {
+
+ private final Scheduler scheduler;
+
+ public QuartzEndpoint(Scheduler scheduler) {
+ Assert.notNull(scheduler, "Scheduler must not be null");
+ this.scheduler = scheduler;
+ }
+
+ @ReadOperation
+ public Map quartzReport() {
+ Map result = new LinkedHashMap<>();
+ try {
+ for (String groupName : this.scheduler.getJobGroupNames()) {
+ List jobs = this.scheduler
+ .getJobKeys(GroupMatcher.jobGroupEquals(groupName)).stream()
+ .map(JobKey::getName).collect(Collectors.toList());
+ result.put(groupName, jobs);
+ }
+ }
+ catch (SchedulerException ignored) {
+ }
+ return result;
+ }
+
+ @ReadOperation
+ public QuartzJob quartzJob(@Selector String groupName, @Selector String jobName) {
+ try {
+ JobKey jobKey = JobKey.jobKey(jobName, groupName);
+ JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
+ List extends Trigger> triggers = this.scheduler.getTriggersOfJob(jobKey);
+ return new QuartzJob(jobDetail, triggers);
+ }
+ catch (SchedulerException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Details of a {@link Job Quartz Job}.
+ */
+ public static final class QuartzJob {
+
+ private final String jobGroup;
+
+ private final String jobName;
+
+ private final String description;
+
+ private final String className;
+
+ private final List triggers = new ArrayList<>();
+
+ QuartzJob(JobDetail jobDetail, List extends Trigger> triggers) {
+ this.jobGroup = jobDetail.getKey().getGroup();
+ this.jobName = jobDetail.getKey().getName();
+ this.description = jobDetail.getDescription();
+ this.className = jobDetail.getJobClass().getName();
+ triggers.forEach(trigger -> this.triggers.add(new QuartzTrigger(trigger)));
+ }
+
+ public String getJobGroup() {
+ return this.jobGroup;
+ }
+
+ public String getJobName() {
+ return this.jobName;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public String getClassName() {
+ return this.className;
+ }
+
+ public List getTriggers() {
+ return this.triggers;
+ }
+
+ }
+
+ /**
+ * Details of a {@link Trigger Quartz Trigger}.
+ */
+ public static final class QuartzTrigger {
+
+ private final String triggerGroup;
+
+ private final String triggerName;
+
+ private final String description;
+
+ private final String calendarName;
+
+ private final Date startTime;
+
+ private final Date endTime;
+
+ private final Date previousFireTime;
+
+ private final Date nextFireTime;
+
+ private final Date finalFireTime;
+
+ QuartzTrigger(Trigger trigger) {
+ this.triggerGroup = trigger.getKey().getGroup();
+ this.triggerName = trigger.getKey().getName();
+ this.description = trigger.getDescription();
+ this.calendarName = trigger.getCalendarName();
+ this.startTime = trigger.getStartTime();
+ this.endTime = trigger.getEndTime();
+ this.previousFireTime = trigger.getPreviousFireTime();
+ this.nextFireTime = trigger.getNextFireTime();
+ this.finalFireTime = trigger.getFinalFireTime();
+ }
+
+ public String getTriggerGroup() {
+ return this.triggerGroup;
+ }
+
+ public String getTriggerName() {
+ return this.triggerName;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public String getCalendarName() {
+ return this.calendarName;
+ }
+
+ public Date getStartTime() {
+ return this.startTime;
+ }
+
+ public Date getEndTime() {
+ return this.endTime;
+ }
+
+ public Date getPreviousFireTime() {
+ return this.previousFireTime;
+ }
+
+ public Date getNextFireTime() {
+ return this.nextFireTime;
+ }
+
+ public Date getFinalFireTime() {
+ return this.finalFireTime;
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/package-info.java
new file mode 100644
index 000000000000..0f27e990dcc6
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/quartz/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Actuator support for Quartz Scheduler.
+ */
+package org.springframework.boot.actuate.quartz;
diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointTests.java
new file mode 100644
index 000000000000..743cd385eaef
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/quartz/QuartzEndpointTests.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.actuate.quartz;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.Test;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+import org.quartz.impl.matchers.GroupMatcher;
+
+import org.springframework.boot.actuate.quartz.QuartzEndpoint.QuartzJob;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link QuartzEndpoint}.
+ *
+ * @author Vedran Pavic
+ */
+public class QuartzEndpointTests {
+
+ private final Scheduler scheduler = mock(Scheduler.class);
+
+ private final QuartzEndpoint endpoint = new QuartzEndpoint(this.scheduler);
+
+ private final JobDetail jobDetail = JobBuilder.newJob(Job.class)
+ .withIdentity("testJob").build();
+
+ private final Trigger trigger = TriggerBuilder.newTrigger().forJob(this.jobDetail)
+ .withIdentity("testTrigger").build();
+
+ @Test
+ public void quartzReport() throws Exception {
+ String jobGroup = this.jobDetail.getKey().getGroup();
+ given(this.scheduler.getJobGroupNames())
+ .willReturn(Collections.singletonList(jobGroup));
+ given(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroup)))
+ .willReturn(Collections.singleton(this.jobDetail.getKey()));
+ Map quartzReport = this.endpoint.quartzReport();
+ assertThat(quartzReport).hasSize(1);
+ }
+
+ @Test
+ public void quartzJob() throws Exception {
+ JobKey jobKey = this.jobDetail.getKey();
+ given(this.scheduler.getJobDetail(jobKey)).willReturn(this.jobDetail);
+ given(this.scheduler.getTriggersOfJob(jobKey))
+ .willAnswer(invocation -> Collections.singletonList(this.trigger));
+ QuartzJob quartzJob = this.endpoint.quartzJob(jobKey.getGroup(),
+ jobKey.getName());
+ assertThat(quartzJob.getJobGroup()).isEqualTo(jobKey.getGroup());
+ assertThat(quartzJob.getJobName()).isEqualTo(jobKey.getName());
+ assertThat(quartzJob.getClassName())
+ .isEqualTo(this.jobDetail.getJobClass().getName());
+ assertThat(quartzJob.getTriggers()).hasSize(1);
+ assertThat(quartzJob.getTriggers().get(0).getTriggerGroup())
+ .isEqualTo(this.trigger.getKey().getGroup());
+ assertThat(quartzJob.getTriggers().get(0).getTriggerName())
+ .isEqualTo(this.trigger.getKey().getName());
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index ea907afe4fdd..22a305ce070e 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -1191,6 +1191,12 @@ content into your application; rather pick only the properties that you need.
management.endpoint.scheduledtasks.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
management.endpoint.scheduledtasks.enabled= # Enable the scheduled tasks endpoint.
+ # QUARTZ ENDPOINT ({sc-spring-boot-actuator}/audit/QuartzEndpoint.{sc-ext}[QuartzEndpoint])
+ endpoints.quartz.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
+ endpoints.quartz.enabled= # Enable the quartz endpoint.
+ endpoints.quartz.jmx.enabled= # Expose the quartz endpoint as a JMX MBean.
+ endpoints.quartz.web.enabled= # Expose the quartz endpoint as a Web endpoint.
+
# SESSIONS ENDPOINT ({sc-spring-boot-actuator}/session/SessionsEndpoint.{sc-ext}[SessionsEndpoint])
management.endpoint.sessions.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
management.endpoint.sessions.enabled= # Enable the sessions endpoint.
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc
index 0ad0e503d957..ab5ca52e0cb2 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc
@@ -101,6 +101,9 @@ The following technology-agnostic endpoints are available:
|`mappings`
|Displays a collated list of all `@RequestMapping` paths.
+|`quartz`
+|Shows information about Quartz Scheduler jobs.
+
|`scheduledtasks`
|Displays the scheduled tasks in your application.
diff --git a/spring-boot-samples/spring-boot-sample-quartz/pom.xml b/spring-boot-samples/spring-boot-sample-quartz/pom.xml
index ae3d5d553c71..0317bf893975 100644
--- a/spring-boot-samples/spring-boot-sample-quartz/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-quartz/pom.xml
@@ -15,6 +15,10 @@
${basedir}/../..
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
org.springframework.boot
spring-boot-starter-quartz