-
+
diff --git a/src/main/content/jcr_root/apps/groovyconsole/components/console/history.html b/src/main/content/jcr_root/apps/groovyconsole/components/console/history.html
index 2f0b88de..28463fcd 100644
--- a/src/main/content/jcr_root/apps/groovyconsole/components/console/history.html
+++ b/src/main/content/jcr_root/apps/groovyconsole/components/console/history.html
@@ -39,6 +39,7 @@
|
|
Date |
+ Job Title |
Script |
|
|
diff --git a/src/main/content/jcr_root/apps/groovyconsole/components/console/scheduled-jobs.html b/src/main/content/jcr_root/apps/groovyconsole/components/console/scheduled-jobs.html
index 1283104b..983092ab 100644
--- a/src/main/content/jcr_root/apps/groovyconsole/components/console/scheduled-jobs.html
+++ b/src/main/content/jcr_root/apps/groovyconsole/components/console/scheduled-jobs.html
@@ -1,4 +1,4 @@
-
+
Scheduled Jobs
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/GroovyConsoleService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/GroovyConsoleService.groovy
index 479811f9..f2660238 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/GroovyConsoleService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/GroovyConsoleService.groovy
@@ -1,5 +1,6 @@
package com.icfolson.aem.groovy.console
+import com.icfolson.aem.groovy.console.api.ActiveJob
import com.icfolson.aem.groovy.console.api.JobProperties
import com.icfolson.aem.groovy.console.api.context.ScriptContext
import com.icfolson.aem.groovy.console.api.context.ScriptData
@@ -34,4 +35,11 @@ interface GroovyConsoleService {
* @return true if job was successfully added
*/
boolean addScheduledJob(JobProperties jobProperties)
+
+ /**
+ * Get a list of all active jobs.
+ *
+ * @return list of active jobs
+ */
+ List getActiveJobs()
}
\ No newline at end of file
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/api/ActiveJob.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/api/ActiveJob.groovy
new file mode 100644
index 00000000..8997460e
--- /dev/null
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/api/ActiveJob.groovy
@@ -0,0 +1,38 @@
+package com.icfolson.aem.groovy.console.api
+
+import com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants
+import com.icfolson.aem.groovy.console.utils.GroovyScriptUtils
+import groovy.transform.Memoized
+import groovy.transform.TupleConstructor
+import org.apache.sling.event.jobs.Job
+
+@TupleConstructor
+class ActiveJob {
+
+ Job job
+
+ String getFormattedStartTime() {
+ job.processingStarted.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY)
+ }
+
+ String getId() {
+ job.id
+ }
+
+ String getTitle() {
+ jobProperties.jobTitle
+ }
+
+ String getDescription() {
+ jobProperties.jobDescription
+ }
+
+ String getScript() {
+ GroovyScriptUtils.getScriptPreview(jobProperties.script)
+ }
+
+ @Memoized
+ JobProperties getJobProperties() {
+ JobProperties.fromJob(job)
+ }
+}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/audit/AuditService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/audit/AuditService.groovy
index 9a8a497c..b9a7db79 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/audit/AuditService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/audit/AuditService.groovy
@@ -67,4 +67,13 @@ interface AuditService {
* @return list of audit records in the given date range
*/
List getAuditRecords(String userId, Calendar startDate, Calendar endDate)
+
+ /**
+ * Get a list of scheduled job audit records for the given date range.
+ *
+ * @param startDate start date
+ * @param endDate end date
+ * @return list of scheduled job audit records in the given date range
+ */
+ List getScheduledJobAuditRecords(Calendar startDate, Calendar endDate)
}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/audit/impl/DefaultAuditService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/audit/impl/DefaultAuditService.groovy
index 355c756d..3d8f38bf 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/audit/impl/DefaultAuditService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/audit/impl/DefaultAuditService.groovy
@@ -164,16 +164,12 @@ class DefaultAuditService implements AuditService {
@Override
List getAuditRecords(String userId, Calendar startDate, Calendar endDate) {
- getAllAuditRecords(userId).findAll { auditRecord ->
- def auditRecordDate = auditRecord.date
-
- auditRecordDate.set(Calendar.HOUR_OF_DAY, 0)
- auditRecordDate.set(Calendar.MINUTE, 0)
- auditRecordDate.set(Calendar.SECOND, 0)
- auditRecordDate.set(Calendar.MILLISECOND, 0)
+ getAuditRecordsForDateRange(getAllAuditRecords(userId), startDate, endDate)
+ }
- !auditRecordDate.before(startDate) && !auditRecordDate.after(endDate)
- }
+ @Override
+ List getScheduledJobAuditRecords(Calendar startDate, Calendar endDate) {
+ getAuditRecordsForDateRange(allScheduledJobAuditRecords, startDate, endDate)
}
@Activate
@@ -280,6 +276,19 @@ class DefaultAuditService implements AuditService {
auditRecords
}
+ private List getAuditRecordsForDateRange(List auditRecords, Calendar startDate, Calendar endDate) {
+ auditRecords.findAll { auditRecord ->
+ def auditRecordDate = auditRecord.date
+
+ auditRecordDate.set(Calendar.HOUR_OF_DAY, 0)
+ auditRecordDate.set(Calendar.MINUTE, 0)
+ auditRecordDate.set(Calendar.SECOND, 0)
+ auditRecordDate.set(Calendar.MILLISECOND, 0)
+
+ !auditRecordDate.before(startDate) && !auditRecordDate.after(endDate)
+ }
+ }
+
private T withResourceResolver(Closure closure) {
resourceResolverFactory.getServiceResourceResolver(null).withCloseable(closure)
}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/components/ActiveJobsPanel.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/components/ActiveJobsPanel.groovy
new file mode 100644
index 00000000..ad0d8e00
--- /dev/null
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/components/ActiveJobsPanel.groovy
@@ -0,0 +1,18 @@
+package com.icfolson.aem.groovy.console.components
+
+import com.icfolson.aem.groovy.console.GroovyConsoleService
+import com.icfolson.aem.groovy.console.api.ActiveJob
+import org.apache.sling.api.SlingHttpServletRequest
+import org.apache.sling.models.annotations.Model
+import org.apache.sling.models.annotations.injectorspecific.OSGiService
+
+@Model(adaptables = SlingHttpServletRequest)
+class ActiveJobsPanel {
+
+ @OSGiService
+ private GroovyConsoleService groovyConsoleService
+
+ List getActiveJobs() {
+ groovyConsoleService.activeJobs
+ }
+}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/components/Body.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/components/Body.groovy
index 31397205..e7f35810 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/components/Body.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/components/Body.groovy
@@ -1,5 +1,6 @@
package com.icfolson.aem.groovy.console.components
+import com.icfolson.aem.groovy.console.GroovyConsoleService
import com.icfolson.aem.groovy.console.audit.AuditRecord
import com.icfolson.aem.groovy.console.audit.AuditService
import com.icfolson.aem.groovy.console.configuration.ConfigurationService
@@ -7,9 +8,9 @@ import groovy.json.JsonBuilder
import org.apache.sling.api.SlingHttpServletRequest
import org.apache.sling.models.annotations.Model
import org.apache.sling.models.annotations.injectorspecific.OSGiService
+import org.apache.sling.models.annotations.injectorspecific.Self
import javax.annotation.PostConstruct
-import javax.inject.Inject
import static com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants.SCRIPT
import static com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants.USER_ID
@@ -20,12 +21,15 @@ class Body {
@OSGiService
private AuditService auditService
- @Inject
- private SlingHttpServletRequest request
-
@OSGiService
private ConfigurationService configurationService
+ @OSGiService
+ private GroovyConsoleService groovyConsoleService
+
+ @Self
+ private SlingHttpServletRequest request
+
private AuditRecord auditRecord
@PostConstruct
@@ -46,6 +50,10 @@ class Body {
configurationService.hasScheduledJobPermission(request)
}
+ boolean isHasActiveJobs() {
+ groovyConsoleService.activeJobs
+ }
+
boolean isAuditEnabled() {
!configurationService.auditDisabled
}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/components/HistoryPanel.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/components/HistoryPanel.groovy
index b41e6b9c..581a3065 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/components/HistoryPanel.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/components/HistoryPanel.groovy
@@ -4,8 +4,7 @@ import com.icfolson.aem.groovy.console.audit.AuditService
import org.apache.sling.api.SlingHttpServletRequest
import org.apache.sling.models.annotations.Model
import org.apache.sling.models.annotations.injectorspecific.OSGiService
-
-import javax.inject.Inject
+import org.apache.sling.models.annotations.injectorspecific.Self
@Model(adaptables = SlingHttpServletRequest)
class HistoryPanel {
@@ -13,7 +12,7 @@ class HistoryPanel {
@OSGiService
private AuditService auditService
- @Inject
+ @Self
private SlingHttpServletRequest request
Boolean isHasAuditRecords() {
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/configuration/ConfigurationService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/configuration/ConfigurationService.groovy
index 983e2971..786d4377 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/configuration/ConfigurationService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/configuration/ConfigurationService.groovy
@@ -58,4 +58,11 @@ interface ConfigurationService {
* @return if true, display all audit records
*/
boolean isDisplayAllAuditRecords()
+
+ /**
+ * Get the thread timeout value in seconds. Scripts will be interrupted when the timeout value is reached. If zero, no timeout will be enforced.
+ *
+ * @return thread timeout
+ */
+ long getThreadTimeout()
}
\ No newline at end of file
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy
index f162a21d..b2a3b621 100755
--- a/src/main/groovy/com/icfolson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/configuration/impl/DefaultConfigurationService.groovy
@@ -39,6 +39,8 @@ class DefaultConfigurationService implements ConfigurationService {
private boolean displayAllAuditRecords
+ private long threadTimeout
+
@Override
boolean hasPermission(SlingHttpServletRequest request) {
isAdminOrAllowedGroupMember(request, allowedGroups)
@@ -74,6 +76,11 @@ class DefaultConfigurationService implements ConfigurationService {
displayAllAuditRecords
}
+ @Override
+ long getThreadTimeout() {
+ threadTimeout
+ }
+
@Activate
@Modified
@Synchronized
@@ -85,6 +92,7 @@ class DefaultConfigurationService implements ConfigurationService {
vanityPathEnabled = properties.vanityPathEnabled()
auditDisabled = properties.auditDisabled()
displayAllAuditRecords = properties.auditDisplayAll()
+ threadTimeout = properties.threadTimeout()
}
private boolean isAdminOrAllowedGroupMember(SlingHttpServletRequest request, Set groupIds) {
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy
index 69dbe954..f583e839 100755
--- a/src/main/groovy/com/icfolson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/impl/DefaultGroovyConsoleService.groovy
@@ -4,6 +4,7 @@ import com.day.cq.commons.jcr.JcrConstants
import com.day.cq.commons.jcr.JcrUtil
import com.google.common.net.MediaType
import com.icfolson.aem.groovy.console.GroovyConsoleService
+import com.icfolson.aem.groovy.console.api.ActiveJob
import com.icfolson.aem.groovy.console.api.JobProperties
import com.icfolson.aem.groovy.console.api.context.ScriptContext
import com.icfolson.aem.groovy.console.api.context.ScriptData
@@ -17,11 +18,13 @@ import com.icfolson.aem.groovy.console.response.SaveScriptResponse
import com.icfolson.aem.groovy.console.response.impl.DefaultRunScriptResponse
import com.icfolson.aem.groovy.console.response.impl.DefaultSaveScriptResponse
import groovy.transform.Synchronized
+import groovy.transform.TimedInterrupt
import groovy.util.logging.Slf4j
import org.apache.jackrabbit.util.Text
import org.apache.sling.event.jobs.JobManager
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.customizers.CompilationCustomizer
import org.osgi.service.component.annotations.Component
import org.osgi.service.component.annotations.Reference
@@ -127,6 +130,13 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {
new DefaultSaveScriptResponse(fileName)
}
+ @Override
+ List getActiveJobs() {
+ jobManager.findJobs(JobManager.QueryType.ACTIVE, GroovyConsoleConstants.JOB_TOPIC, 0, null).collect { job ->
+ new ActiveJob(job)
+ }
+ }
+
@Override
boolean addScheduledJob(JobProperties jobProperties) {
if (jobProperties.cronExpression) {
@@ -182,7 +192,14 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {
}
private CompilerConfiguration getConfiguration() {
- new CompilerConfiguration().addCompilationCustomizers(extensionService.compilationCustomizers
+ def configuration = new CompilerConfiguration()
+
+ if (configurationService.threadTimeout > 0) {
+ // add timed interrupt using configured timeout value
+ configuration.addCompilationCustomizers(new ASTTransformationCustomizer(value: configurationService.threadTimeout, TimedInterrupt))
+ }
+
+ configuration.addCompilationCustomizers(extensionService.compilationCustomizers
as CompilationCustomizer[])
}
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/servlets/AuditServlet.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/servlets/AuditServlet.groovy
index b9cb80a1..fc7d9696 100644
--- a/src/main/groovy/com/icfolson/aem/groovy/console/servlets/AuditServlet.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/servlets/AuditServlet.groovy
@@ -57,6 +57,7 @@ class AuditServlet extends AbstractJsonResponseServlet {
[
date: auditRecord.date.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY),
scriptPreview: GroovyScriptUtils.getScriptPreview(auditRecord.script),
+ jobTitle: auditRecord.jobProperties.jobTitle,
userId: auditRecord.userId,
script: auditRecord.script,
data: auditRecord.data,
@@ -72,16 +73,23 @@ class AuditServlet extends AbstractJsonResponseServlet {
def startDateParameter = request.getParameter(GroovyConsoleConstants.START_DATE)
def endDateParameter = request.getParameter(GroovyConsoleConstants.END_DATE)
- def auditRecords
+ def auditRecords = [] as List
if (!startDateParameter || !endDateParameter) {
- auditRecords = auditService.getAllAuditRecords(request.resourceResolver.userID)
+ if (configurationService.hasScheduledJobPermission(request)) {
+ auditRecords.addAll(auditService.allScheduledJobAuditRecords)
+ }
+
+ auditRecords.addAll(auditService.getAllAuditRecords(request.resourceResolver.userID))
} else {
- def startDate = Date.parse(DATE_FORMAT, startDateParameter)
- def endDate = Date.parse(DATE_FORMAT, endDateParameter)
+ def startDate = Date.parse(DATE_FORMAT, startDateParameter).toCalendar()
+ def endDate = Date.parse(DATE_FORMAT, endDateParameter).toCalendar()
+
+ if (configurationService.hasScheduledJobPermission(request)) {
+ auditRecords.addAll(auditService.getScheduledJobAuditRecords(startDate, endDate))
+ }
- auditRecords = auditService.getAuditRecords(request.resourceResolver.userID, startDate.toCalendar(),
- endDate.toCalendar())
+ auditRecords.addAll(auditService.getAuditRecords(request.resourceResolver.userID, startDate, endDate))
}
auditRecords.sort { a, b -> b.date.timeInMillis <=> a.date.timeInMillis }
diff --git a/src/main/groovy/com/icfolson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy b/src/main/groovy/com/icfolson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy
index 3849c857..84c4587c 100755
--- a/src/main/groovy/com/icfolson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy
+++ b/src/main/groovy/com/icfolson/aem/groovy/console/servlets/ScheduledJobsServlet.groovy
@@ -63,7 +63,7 @@ class ScheduledJobsServlet extends AbstractJsonResponseServlet {
new ImmutableMap.Builder()
.putAll(scheduledJobInfo.jobProperties)
- .put("downloadUrl", auditRecords ? auditRecords.last().downloadUrl : null)
+ .put("downloadUrl", (auditRecords ? auditRecords.last().downloadUrl : null) ?: "")
.put("scriptPreview", GroovyScriptUtils.getScriptPreview(scheduledJobInfo.jobProperties[SCRIPT] as String))
.put("nextExecutionDate", scheduledJobInfo.nextScheduledExecution.format(GroovyConsoleConstants.DATE_FORMAT_DISPLAY))
.build()
diff --git a/src/main/java/com/icfolson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java b/src/main/java/com/icfolson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java
index dc299e3a..9486ac55 100644
--- a/src/main/java/com/icfolson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java
+++ b/src/main/java/com/icfolson/aem/groovy/console/configuration/impl/ConfigurationServiceProperties.java
@@ -34,4 +34,8 @@
@AttributeDefinition(name = "Display All Audit Records?",
description = "If enabled, all audit records (including records for other users) will be displayed in the console history.")
boolean auditDisplayAll() default false;
+
+ @AttributeDefinition(name = "Thread Timeout",
+ description = "Time in seconds that scripts are allowed to execute before being interrupted. If 0, no timeout is enforced.")
+ long threadTimeout() default 0;
}
\ No newline at end of file