diff --git a/docs/Running.adoc b/docs/Running.adoc index ca5ab33..e545f27 100644 --- a/docs/Running.adoc +++ b/docs/Running.adoc @@ -36,6 +36,10 @@ image::../assets/monitor.png[Monitor Jobs] See link:Monitoring.adoc[Monitoring / Validating the Content Sync] for information on evaluating the returned information. +=== Stopping a Job + +From the main screen, enter "s" to stop an existing job. You will be prompted to enter a job id. Enter the job id that you wish to terminate. + ==== Configuration diff --git a/grabbit.sh b/grabbit.sh index d13851a..b57d4ad 100755 --- a/grabbit.sh +++ b/grabbit.sh @@ -88,6 +88,19 @@ function monitorStatus { done } +function stopJob { + echo "Enter jobID to stop, or \"b\" to go back" + read selection + if [ "$selection" == "b" ]; then + echo "*****************************************************" + return + fi + statusJson=`curl -s -u $username:$password --request DELETE $client$GRABBIT_JOB"?jobId="$selection` + echo + echo "$statusJson" +} + + clear echo $SET_BLUE echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" @@ -105,12 +118,14 @@ echo "Client Password :" read -s password while true; do - echo "Enter \"n\" for new job request, \"m\" to monitor, or \"q\" to quit" + echo "Enter \"n\" for new job request, \"m\" to monitor, \"s\" to stop a job, or \"q\" to quit" read selection if [ "$selection" == "n" ]; then newGrabbitRequest elif [ "$selection" == "m" ]; then monitorStatus + elif [ "$selection" == "s" ]; then + stopJob elif [ "$selection" == "q" ]; then exit 0; else diff --git a/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy b/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy index eb71470..2a71788 100644 --- a/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy +++ b/src/main/groovy/com/twcable/grabbit/client/servlets/GrabbitJobServlet.groovy @@ -32,10 +32,14 @@ import org.apache.sling.api.SlingHttpServletRequest import org.apache.sling.api.SlingHttpServletResponse import org.apache.sling.api.servlets.SlingAllMethodsServlet import org.springframework.batch.core.explore.JobExplorer +import org.springframework.batch.core.launch.JobExecutionNotRunningException +import org.springframework.batch.core.launch.NoSuchJobExecutionException +import org.springframework.batch.core.launch.support.SimpleJobOperator import org.springframework.context.ConfigurableApplicationContext import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST import static javax.servlet.http.HttpServletResponse.SC_OK +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND /** * This servlet is used to manage Grabbit jobs. @@ -49,7 +53,7 @@ import static javax.servlet.http.HttpServletResponse.SC_OK */ @Slf4j @CompileStatic -@SlingServlet(methods = ['GET', 'PUT'], resourceTypes = ['twcable:grabbit/job']) +@SlingServlet(methods = ['GET', 'PUT', 'DELETE'], resourceTypes = ['twcable:grabbit/job']) class GrabbitJobServlet extends SlingAllMethodsServlet { //A "special" meta-jobID that allows for the status of all jobs to be queried. @@ -147,6 +151,38 @@ class GrabbitJobServlet extends SlingAllMethodsServlet { response.writer.write(new JsonBuilder(jobExecutionIds).toString()) } + @Override + protected void doDelete(SlingHttpServletRequest request, SlingHttpServletResponse response) { + String jobExecutionId = request.getParameter("jobId") ?: "" + + if(jobExecutionId == ALL_JOBS_ID) { + response.setStatus(SC_BAD_REQUEST) + response.writer.write("Stopping 'all' jobs is not supported. Please specify single job id") + return + } + if(!jobExecutionId.isLong()) { + log.warn "Parameter ${jobExecutionId} 'jobId' is invalid" + response.status = SC_BAD_REQUEST + response.writer.write("Parameter 'jobId' is invalid") + return + } + try { + SimpleJobOperator jobOperator = configurableApplicationContext.getBean(SimpleJobOperator) + jobOperator.stop(jobExecutionId.toLong()) + response.status = SC_OK + response.writer.write("Job ${jobExecutionId} Successfully Stopped") + } + catch (NoSuchJobExecutionException noSuchJobExc){ + response.status = SC_NOT_FOUND + response.writer.write("No suhc job exists with id ${jobExecutionId}") + } + catch (JobExecutionNotRunningException jobNotRunningExc){ + response.status = SC_OK + response.writer.write("Job already complete for id ${jobExecutionId}. Nothing to Stop") + } + + } + /** * Will return the status of a job from the {@link org.springframework.batch.core.explore.JobExplorer} used in JSON format. * @param jobId The jobID to get status. diff --git a/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy b/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy index 25fad75..0aa458f 100644 --- a/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy +++ b/src/test/groovy/com/twcable/grabbit/client/GrabbitJobServletSpec.groovy @@ -27,6 +27,9 @@ import org.apache.sling.api.resource.Resource import org.apache.sling.api.resource.ResourceMetadata import org.springframework.batch.core.JobParameters import org.springframework.batch.core.explore.JobExplorer +import org.springframework.batch.core.launch.JobExecutionNotRunningException +import org.springframework.batch.core.launch.NoSuchJobExecutionException +import org.springframework.batch.core.launch.support.SimpleJobOperator import org.springframework.context.ConfigurableApplicationContext import spock.lang.Specification import spock.lang.Subject @@ -37,6 +40,7 @@ import static com.twcable.grabbit.client.servlets.GrabbitJobServlet.ALL_JOBS_ID import static com.twcable.grabbit.testutil.StubInputStream.inputStream import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST import static javax.servlet.http.HttpServletResponse.SC_OK +import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND @Subject(GrabbitJobServlet) class GrabbitJobServletSpec extends Specification { @@ -232,4 +236,38 @@ class GrabbitJobServletSpec extends Specification { inputStream << [inputStream(" "), inputStream("foo: 'foo'")] //One causes SnakeYAML to produce a null config map, and the other does not pass our validations (missing values) } + + def "Stop job response check with differnt set of jobId parameter"() { + given: + SlingHttpServletRequest request = Mock(SlingHttpServletRequest) { + getParameter("jobId") >> inputJobId + } + SlingHttpServletResponse response = Mock(SlingHttpServletResponse) { + getWriter() >> Mock(PrintWriter) + } + GrabbitJobServlet servlet = new GrabbitJobServlet() + final applicationContext = Mock(ConfigurableApplicationContext) { + getBean(SimpleJobOperator) >> Mock(SimpleJobOperator) { + stop(123L) >> true + stop(222L) >> {throw new NoSuchJobExecutionException("Job does not exist")} + stop(333L) >> {throw new JobExecutionNotRunningException("Job not running")} + } + } + servlet.setConfigurableApplicationContext(applicationContext) + + when: + servlet.doDelete(request, response) + + then: + 1 * response.setStatus(expectedResponse) + + where: + inputJobId | expectedResponse + 123L | SC_OK + 222L | SC_NOT_FOUND + 333L | SC_OK + "aaa" | SC_BAD_REQUEST + "" | SC_BAD_REQUEST + } + }