BATCHEE-51 add stop and restart to SimpleRest api
Usage via:
* .../jbatch/rest/stop/${executionId}
* .../jbatch/rest/restart/${executionId}
diff --git a/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java b/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
index 6f6d6dc..b86239f 100644
--- a/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
+++ b/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
@@ -22,6 +22,8 @@
import java.util.Map;
import java.util.Properties;
+import javax.batch.operations.JobExecutionAlreadyCompleteException;
+import javax.batch.operations.JobExecutionNotRunningException;
import javax.batch.operations.JobOperator;
import javax.batch.operations.JobStartException;
import javax.batch.operations.NoSuchJobExecutionException;
@@ -38,6 +40,8 @@
public static final String OP_START = "start/";
public static final String OP_STATUS = "status/";
+ public static final String OP_STOP = "stop/";
+ public static final String OP_RESTART = "restart/";
public static final long NO_JOB_ID = -1L;
@@ -58,29 +62,18 @@
startBatch(path.substring(OP_START.length()), req, resp);
} else if (path != null && path.startsWith(OP_STATUS)) {
batchStatus(path.substring(OP_STATUS.length()), req, resp);
+ } else if (path != null && path.startsWith(OP_STOP)) {
+ batchStop(path.substring(OP_STOP.length()), req, resp);
+ } else if (path != null && path.startsWith(OP_RESTART)) {
+ batchRestart(path.substring(OP_RESTART.length()), req, resp);
} else {
unknownCommand(path, resp);
}
}
private void startBatch(String batchName, HttpServletRequest req, HttpServletResponse resp) {
- Properties jobProperties = new Properties();
- Map<String, String[]> parameterMap = req.getParameterMap();
- for (Map.Entry<String, String[]> paramEntry : parameterMap.entrySet()) {
- String key = paramEntry.getKey();
- if (key == null || key.length() == 0) {
- reportFailure(NO_JOB_ID, resp, "Parameter key must be set");
- return;
- }
-
- String[] vals = paramEntry.getValue();
- if (vals == null || vals.length != 1) {
- reportFailure(NO_JOB_ID, resp, "Exactly one value must be set for each parameter (parameter name=" + key + ")");
- return;
- }
- String val = vals[0];
- jobProperties.put(key, val);
- }
+ Properties jobProperties = extractJobProperties(req, resp);
+ if (jobProperties == null) { return; }
try {
long jobId = jobOperator.start(batchName, jobProperties);
@@ -95,19 +88,11 @@
private void batchStatus(String batchId, HttpServletRequest req, HttpServletResponse resp)
{
- if (batchId == null || batchId.isEmpty()) {
- reportFailure(NO_JOB_ID, resp, "no executionId given");
+ Long executionId = extractExecutionId(batchId, resp);
+ if (executionId == null) {
return;
}
- long executionId = NO_JOB_ID;
-
- try {
- executionId = Long.valueOf(batchId);
- } catch(NumberFormatException nfe) {
- reportFailure(NO_JOB_ID, resp, "executionId must be numeric, but is " + batchId);
- }
-
try {
JobExecution jobExecution = jobOperator.getJobExecution(executionId);
BatchStatus batchStatus = jobExecution.getBatchStatus();
@@ -115,16 +100,63 @@
} catch (NoSuchJobExecutionException noSuchJob) {
reportFailure(executionId, resp, "NoSuchJob");
} catch (Exception generalException) {
- StringBuilder msg = new StringBuilder("NoSuchJob");
+ StringBuilder msg = new StringBuilder("Failure in BatchExecution");
appendExceptionMsg(msg, generalException);
reportFailure(executionId, resp, msg.toString());
}
}
+ private void batchStop(String batchId, HttpServletRequest req, HttpServletResponse resp) {
+ Long executionId = extractExecutionId(batchId, resp);
+ if (executionId == null) {
+ return;
+ }
+
+ try {
+ jobOperator.stop(executionId);
+ reportSuccess(executionId, resp, BatchStatus.STOPPING.toString());
+ } catch (NoSuchJobExecutionException noSuchJob) {
+ reportFailure(executionId, resp, "NoSuchJob");
+ } catch (JobExecutionNotRunningException notRunningException) {
+ reportFailure(executionId, resp, "JobExecutionNotRunning");
+ } catch (Exception generalException) {
+ StringBuilder msg = new StringBuilder("Failure in BatchExecution");
+ appendExceptionMsg(msg, generalException);
+ reportFailure(executionId, resp, msg.toString());
+ }
+ }
+
+ private void batchRestart(String batchId, HttpServletRequest req, HttpServletResponse resp) {
+ Long executionId = extractExecutionId(batchId, resp);
+ if (executionId == null) {
+ return;
+ }
+
+ Properties jobProperties = extractJobProperties(req, resp);
+
+ try {
+ jobOperator.restart(executionId, jobProperties);
+ } catch (NoSuchJobExecutionException noSuchJob) {
+ reportFailure(executionId, resp, "NoSuchJob");
+ } catch (JobExecutionAlreadyCompleteException alreadyCompleted) {
+ reportFailure(executionId, resp, "NoSuchJob");
+ } catch (Exception generalException) {
+ StringBuilder msg = new StringBuilder("Failure in BatchExecution");
+ appendExceptionMsg(msg, generalException);
+ reportFailure(executionId, resp, msg.toString());
+ }
+ }
+
+
private void unknownCommand(String path, HttpServletResponse resp) {
StringBuilder msg = new StringBuilder("Unknown command:");
msg.append(path).append('\n');
+ msg.append("The returned response if of MIME type text/plain and contains the following information\n");
+ msg.append(" {jobExecutionId} (or -1 if no executionId was detected)\\n\n");
+ msg.append(" OK (or FAILURE)\\n\n");
+ msg.append(" followed by command specific information\n");
+
msg.append("\nKnown commands are:\n\n");
msg.append("* ").append(OP_START).append(" - start a new batch job\n");
msg.append(" Sample: http://localhost:8080/myapp/jbatch/rest/start/myjobname?param1=x¶m2=y\n");
@@ -134,14 +166,52 @@
msg.append(" Sample: http://localhost:8080/myapp/jbatch/rest/status/23\n");
msg.append(" will return the state of executionId 23\n\n");
- msg.append("The returned response if of MIME type text/plain and contains the following information\n");
- msg.append(" {jobExecutionId} (or -1 if no executionId was detected)\\n\n");
- msg.append(" OK (or FAILURE)\\n\n");
- msg.append(" followed by command specific information\n");
+ msg.append("* ").append(OP_STOP).append(" - stop the job with the given executionId \n");
+ msg.append(" Sample: http://localhost:8080/myapp/jbatch/rest/stop/23\n");
+ msg.append(" will stop the job with executionId 23\n\n");
+
+ msg.append("* ").append(OP_RESTART).append(" - restart the job with the given executionId \n");
+ msg.append(" Sample: http://localhost:8080/myapp/jbatch/rest/restart/23\n");
+ msg.append(" will restart the job with executionId 23\n\n");
reportFailure(NO_JOB_ID, resp, msg.toString());
}
+ private Properties extractJobProperties(HttpServletRequest req, HttpServletResponse resp) {
+ Properties jobProperties = new Properties();
+ Map<String, String[]> parameterMap = req.getParameterMap();
+ for (Map.Entry<String, String[]> paramEntry : parameterMap.entrySet()) {
+ String key = paramEntry.getKey();
+ if (key == null || key.length() == 0) {
+ reportFailure(NO_JOB_ID, resp, "Parameter key must be set");
+ return null;
+ }
+
+ String[] vals = paramEntry.getValue();
+ if (vals == null || vals.length != 1) {
+ reportFailure(NO_JOB_ID, resp, "Exactly one value must be set for each parameter (parameter name=" + key + ")");
+ return null;
+ }
+ String val = vals[0];
+ jobProperties.put(key, val);
+ }
+ return jobProperties;
+ }
+
+ private Long extractExecutionId(String batchId, HttpServletResponse resp) {
+ if (batchId == null || batchId.isEmpty()) {
+ reportFailure(NO_JOB_ID, resp, "no executionId given");
+ return null;
+ }
+
+ try {
+ return Long.valueOf(batchId);
+ } catch(NumberFormatException nfe) {
+ reportFailure(NO_JOB_ID, resp, "executionId must be numeric, but is " + batchId);
+ return null;
+ }
+ }
+
private void reportSuccess(long jobId, HttpServletResponse resp, String msg) {
resp.setStatus(HttpServletResponse.SC_OK);
writeContent(resp, Long.toString(jobId) + "\n");
diff --git a/gui/servlet/embedded/src/test/java/org/apache/batchee/servlet/ServletTest.java b/gui/servlet/embedded/src/test/java/org/apache/batchee/servlet/ServletTest.java
index 122b270..d6ed626 100644
--- a/gui/servlet/embedded/src/test/java/org/apache/batchee/servlet/ServletTest.java
+++ b/gui/servlet/embedded/src/test/java/org/apache/batchee/servlet/ServletTest.java
@@ -17,6 +17,7 @@
package org.apache.batchee.servlet;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+import com.gargoylesoftware.htmlunit.TextPage;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
@@ -40,12 +41,55 @@
import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
@RunWith(Arquillian.class)
public class ServletTest {
@ArquillianResource
private URL base;
+ @Deployment(testable = false)
+ public static Archive<?> war() {
+ final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "batchee-gui.war")
+ .addAsWebInfResource(new StringAsset(
+ Descriptors.create(WebAppDescriptor.class)
+ .metadataComplete(true)
+ .createListener()
+ .listenerClass(CreateSomeJobs.class.getName())
+ .up()
+ .createFilter()
+ .filterName("JBatch Private Filter")
+ .filterClass(JBatchServletInitializer.PrivateFilter.class.getName())
+ .up()
+ .createServlet()
+ .servletName("JBatch")
+ .servletClass(JBatchController.class.getName())
+ .loadOnStartup(1)
+ .up()
+ .createFilterMapping()
+ .filterName("JBatch Private Filter")
+ .urlPattern("/*")
+ .up()
+ .createServletMapping()
+ .servletName("JBatch")
+ .urlPattern("/jbatch/*")
+ .up()
+ .exportAsString()), "web.xml")
+ // GUI
+ .addPackages(true, JBatchController.class.getPackage())
+ // test data to create some job things to do this test
+ .addPackage(CreateSomeJobs.class.getPackage())
+ .addAsWebInfResource("META-INF/batch-jobs/init.xml", "classes/META-INF/batch-jobs/init.xml");
+
+ for (final String resource : Arrays.asList("layout.jsp", "jobs.jsp", "job-instances.jsp", "step-executions.jsp",
+ "css/bootstrap.min.3.0.0.css", "js/bootstrap.min.3.0.0.js")) {
+ webArchive.addAsWebResource("META-INF/resources/internal/batchee/" + resource, "internal/batchee/" + resource);
+ }
+
+ return webArchive;
+ }
+
@Test
public void home() throws IOException {
assertEquals("init", extractContent("", "/ul/li/a[1]/text()"));
@@ -67,6 +111,41 @@
client.getPage(base.toExternalForm() + "jbatch/internal/batchee/jobs.jsp");
}
+ @Test
+ public void testSimpleRest() throws IOException, InterruptedException {
+ String textContent = executeSimpleRest("start/init?value=OK&sleep=2");
+ Long executionId = extractExecutionId(textContent);
+
+ Thread.sleep(100L);
+
+ textContent = executeSimpleRest("status/" + executionId);
+ String[] parms = textContent.split("\n");
+ assertTrue(parms.length == 3);
+ assertEquals(BatchStatus.STARTED.toString(), parms[2]);
+ }
+
+ private String executeSimpleRest(String command) throws IOException {
+ final String startUrl = base.toExternalForm() + "jbatch/rest/" + command;
+ final WebClient webClient = newWebClient();
+ final TextPage page = webClient.getPage(startUrl);
+ String textContent = page.getContent();
+ assertNotNull(textContent);
+ assertTrue(textContent.contains("\nOK\n"));
+ extractExecutionId(textContent);
+
+ return textContent;
+ }
+
+ private Long extractExecutionId(String textContent) {
+ String[] parms = textContent.split("\n");
+ assertTrue(parms.length >= 2);
+ Long executionId = Long.valueOf(parms[0]);
+ assertTrue(-1L != executionId);
+
+ return executionId;
+ }
+
+
private String extractContent(final String endUrl, final String xpath) throws IOException {
final String url = base.toExternalForm() + "jbatch/" + endUrl;
final WebClient webClient = newWebClient();
@@ -90,44 +169,5 @@
return webClient;
}
- @Deployment(testable = false)
- public static Archive<?> war() {
- final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "batchee-gui.war")
- .addAsWebInfResource(new StringAsset(
- Descriptors.create(WebAppDescriptor.class)
- .metadataComplete(true)
- .createListener()
- .listenerClass(CreateSomeJobs.class.getName())
- .up()
- .createFilter()
- .filterName("JBatch Private Filter")
- .filterClass(JBatchServletInitializer.PrivateFilter.class.getName())
- .up()
- .createServlet()
- .servletName("JBatch")
- .servletClass(JBatchController.class.getName())
- .loadOnStartup(1)
- .up()
- .createFilterMapping()
- .filterName("JBatch Private Filter")
- .urlPattern("/*")
- .up()
- .createServletMapping()
- .servletName("JBatch")
- .urlPattern("/jbatch/*")
- .up()
- .exportAsString()), "web.xml")
- // GUI
- .addPackages(true, JBatchController.class.getPackage())
- // test data to create some job things to do this test
- .addPackage(CreateSomeJobs.class.getPackage())
- .addAsWebInfResource("META-INF/batch-jobs/init.xml", "classes/META-INF/batch-jobs/init.xml");
- for (final String resource : Arrays.asList("layout.jsp", "jobs.jsp", "job-instances.jsp", "step-executions.jsp",
- "css/bootstrap.min.3.0.0.css", "js/bootstrap.min.3.0.0.js")) {
- webArchive.addAsWebResource("META-INF/resources/internal/batchee/" + resource, "internal/batchee/" + resource);
- }
-
- return webArchive;
- }
}