Java tutorial
package de.zib.gndms.gndmc.gorfx; /* * Copyright 2008-2011 Zuse Institute Berlin (ZIB) * * 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. */ import de.zib.gndms.common.model.gorfx.types.*; import de.zib.gndms.common.rest.Facets; import de.zib.gndms.common.rest.GNDMSResponseHeader; import de.zib.gndms.common.rest.Specifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; import java.util.List; import java.util.UUID; /** * @author try ma ik jo rr a zib * @date 14.03.11 11:38 * @brief Performs all requests necessary for taskflow execution. * * To put the caller in control over the taskflow this class provides * handler methods for the result of imported calls. * * \note The handler methods are only called if the preceding server response * was positive. */ public abstract class AbstractTaskFlowExecClient implements TaskStatusHandler { private GORFXClient gorfxClient; ///< A ready to uses instance of the gorfx client. private TaskFlowClient tfClient; ///< A ready to uses instance of the taskflow client. private TaskClient taskClient; ///< A ready to uses instance of the task client. private long pollingDelay = 1000; ///< delay in ms to poll the task status, once the task is running. /** * @brief Executes a complete task flow. * * @param order The order of the taskflow. * @param dn The DN of the user calling the task flow. * \note here the workflow id is generated on the fly. */ public void execTF(Order order, String dn) { execTF(order, dn, true, null, UUID.randomUUID().toString()); } /** * * @brief Executes a complete task flow. * * This method is imported when you want to understand the * Taskflow protocol. * * @param order The order of the taskflow. * @param dn The DN of the user calling the task flow. * * @param withQuote Activates co-scheduling * @param desiredQuote A quote holding desired time values for * the tasflow execution. * * \note for now the workflow id is generated on the fly. */ public void execTF(Order order, String dn, boolean withQuote, final Quote desiredQuote) { execTF(order, dn, withQuote, desiredQuote, UUID.randomUUID().toString()); } /** * * @brief Executes a complete task flow. * * This method is imported when you want to understand the * Taskflow protocol. * * @param order The order of the taskflow. * @param dn The DN of the user calling the task flow. * * @param withQuote Activates co-scheduling * @param desiredQuote A quote holding desired time values for * the tasflow execution. * @param wid the workflow id */ public void execTF(Order order, String dn, boolean withQuote, final Quote desiredQuote, final String wid) { GNDMSResponseHeader context = setupContext(new GNDMSResponseHeader()); if (null == gorfxClient) { throw new IllegalStateException("You need to set gorfxClient before executing a TaskFlow!"); } /** * \code this is important */ // sends the order and creates the task flow ResponseEntity<Specifier<Facets>> res = gorfxClient.createTaskFlow(order.getTaskFlowType(), order, dn, wid, context); if (!HttpStatus.CREATED.equals(res.getStatusCode())) { throw new RuntimeException("createTaskFlow failed " + res.getStatusCode().name() + " (" + res.getStatusCode() + ")" + " on URL " + gorfxClient.getServiceURL()); } // the taskflow id is stored under "id" in the urlmap String tid = res.getBody().getUriMap().get("id"); Integer q = null; if (withQuote) { if (null == tfClient) { throw new IllegalStateException("No TaskFlowClient set."); } if (desiredQuote != null) { tfClient.setQuote(order.getTaskFlowType(), tid, desiredQuote, dn, wid); } // queries the quotes for the task flow ResponseEntity<List<Specifier<Quote>>> res2 = tfClient.getQuotes(order.getTaskFlowType(), tid, dn, wid); if (!HttpStatus.OK.equals(res2.getStatusCode())) throw new RuntimeException("getQuotes failed " + res2.getStatusCode().name()); // lets the implementors of this class choose a quote q = selectQuote(res2.getBody()); } // // 'til here it is valid to change the order and request new quotes // // accepts quote q and triggers task creation ResponseEntity<Specifier<Facets>> res3 = tfClient.createTask(order.getTaskFlowType(), tid, q, dn, wid); if (!HttpStatus.CREATED.equals(res3.getStatusCode())) throw new RuntimeException("createTask failed " + res3.getStatusCode().name()); final Specifier<Facets> taskSpecifier = res3.getBody(); // let the implementor do smart things with the task specifier handleTaskSpecifier(taskSpecifier); // the task id is stored under "taskId" in the specifiers urlmap waitForFinishOrFail(taskSpecifier, this, taskClient, pollingDelay, dn, wid); /** * \endcode */ } /** * Polls a running task, until its either finished or failed. * * @param taskSpecifier The specifier of the task. * @param statusHandler The handler for the task status, can update some sort of UI. * @param taskClient The task client, which should be used for polling. * @param pollingDelay The pollingDelay, its the delay between polling. * @param dn The user DN. * @param wid The workflow id. * * @return The final task status, finished or failed. */ public static TaskStatus waitForFinishOrFail(final Specifier<Facets> taskSpecifier, final TaskStatusHandler statusHandler, final TaskClient taskClient, final long pollingDelay, final String dn, final String wid) { TaskStatus ts; String taskId = taskSpecifier.getUriMap().get("taskId"); ResponseEntity<TaskStatus> stat; boolean done = false; do { // queries the status of the task execution stat = taskClient.getStatus(taskId, dn, wid); if (!HttpStatus.OK.equals(stat.getStatusCode())) throw new RuntimeException("Task::getStatus failed " + stat.getStatusCode().name()); ts = stat.getBody(); // allows the implementor to do something with the task status statusHandler.handleStatus(ts); try { Thread.sleep(pollingDelay); } catch (InterruptedException e) { throw new RuntimeException(e); } // finished without an error, good(?) if (finished(ts)) { // collect the result ResponseEntity<TaskResult> tr = null; try { tr = taskClient.getResult(taskId, dn, wid); } catch (HttpClientErrorException e) { if (404 == e.getStatusCode().value()) continue; } if (!HttpStatus.OK.equals(tr.getStatusCode())) throw new RuntimeException("Failed to obtain task result " + tr.getStatusCode().name()); // do something with it statusHandler.handleResult(tr.getBody()); done = true; } else if (failed(ts)) { // must be failed, not so good // find out way ResponseEntity<TaskFailure> tf = taskClient.getErrors(taskId, dn, wid); if (!HttpStatus.OK.equals(tf.getStatusCode())) throw new RuntimeException("Failed to obtain task errors " + tf.getStatusCode().name()); // handle the failure statusHandler.handleFailure(tf.getBody()); done = true; } } while (!done); // run 'til the task hits a final state return ts; } /** * Same as the above method, but without a status handler. * * @param taskSpecifier The specifier of the task. * @param taskClient The task client, which should be used for polling. * @param pollingDelay The pollingDelay, its the delay between polling. * @param dn The user DN. * @param wid The workflow id. * * @return The final task status, finished or failed. */ public static TaskStatus waitForFinishOrFail(final Specifier<Facets> taskSpecifier, final TaskClient taskClient, final long pollingDelay, final String dn, final String wid) { return waitForFinishOrFail(taskSpecifier, new LazyStatusHandler(), taskClient, pollingDelay, dn, wid); } /** * Offers implementing clients the possibility to add values to the request context. * * The request context is used to create taskflows and the right place to provide * myProxyTokens. * * @param context The create request context. * @return The augmented context */ protected GNDMSResponseHeader setupContext(final GNDMSResponseHeader context) { // example: context.addMyProxyToken( "c3grid", "foo", "bar" ); return context; } /** * @brief Allows the caller to select a quote. * * @param quotes All available quotes. * * @return The index of the accepted quote. \c null will disable * quote usage. */ protected abstract Integer selectQuote(List<Specifier<Quote>> quotes); /** * @brief Allows additional handling for the task specifier. * * @param ts The task specifier, including all task facets as * payload. */ protected abstract void handleTaskSpecifier(Specifier<Facets> ts); /** * @brief Handler for the task result. * * Override this method to gain access to the task(flow) result an * send it to the user, post process it or store it for later * usage. *@param res The result object. */ public abstract void handleResult(TaskResult res); /** * @brief Handler for task failures. * * Override this method to gain access to the task(flow) error * object, e.g. to send an error-report to someone who cares. * * @param fail The failure object. */ public abstract void handleFailure(TaskFailure fail); /** * @brief Checks if ts is FINISHED. * * @param ts The current task state. * * @return \c true if ts is FINISHED */ private static boolean finished(TaskStatus ts) { return TaskStatus.Status.FINISHED.equals(ts.getStatus()); } /** * @brief Checks if ts is FINISHED. * * @param ts The current task state. * * @return \c true if ts is FINISHED */ private static boolean failed(TaskStatus ts) { return TaskStatus.Status.FAILED.equals(ts.getStatus()); } /** * @brief Delivers the value of ::gorfxClient. * * @return The value of ::gorfxClient. */ public GORFXClient getGorfxClient() { return gorfxClient; } /** * @brief Sets the value of ::gorfxClient to \e gorfxClient. * * @param gorfxClient The new value of ::gorfxClient. */ public void setGorfxClient(GORFXClient gorfxClient) { this.gorfxClient = gorfxClient; } /** * @brief Delivers the value of ::tfClient. * * @return The value of ::tfClient. */ public TaskFlowClient getTfClient() { return tfClient; } /** * @brief Sets the value of ::tfClient to \e tfClient. * * @param tfClient The new value of ::tfClient. */ public void setTfClient(TaskFlowClient tfClient) { this.tfClient = tfClient; } /** * @brief Delivers the value of ::taskClient. * * @return The value of ::taskClient. */ public TaskClient getTaskClient() { return taskClient; } /** * @brief Sets the value of ::taskClient to \e taskClient. * * @param taskClient The new value of ::taskClient. */ public void setTaskClient(TaskClient taskClient) { this.taskClient = taskClient; } /** * @brief Delivers the value of ::pollingDelay. * * @return The value of ::pollingDelay. */ public long getPollingDelay() { return pollingDelay; } /** * @brief Sets the value of ::pollingDelay to \e pollingDelay. * * @param pollingDelay The new value of ::pollingDelay. */ public void setPollingDelay(long pollingDelay) { this.pollingDelay = pollingDelay; } public static class LazyStatusHandler implements TaskStatusHandler { @Override public void handleStatus(final TaskStatus stat) { // this handler is lazy, it does nothing } @Override public void handleResult(final TaskResult body) { // not required here } @Override public void handleFailure(final TaskFailure body) { // not required here } } }