All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.simpleworkflow.flow.common.WorkflowExecutionUtils Maven / Gradle / Ivy

Go to download

The Amazon Web Services SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

The newest version!
/*
 * Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 com.amazonaws.services.simpleworkflow.flow.common;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;

import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.model.CloseStatus;
import com.amazonaws.services.simpleworkflow.model.Decision;
import com.amazonaws.services.simpleworkflow.model.DescribeWorkflowExecutionRequest;
import com.amazonaws.services.simpleworkflow.model.EventType;
import com.amazonaws.services.simpleworkflow.model.ExecutionStatus;
import com.amazonaws.services.simpleworkflow.model.GetWorkflowExecutionHistoryRequest;
import com.amazonaws.services.simpleworkflow.model.History;
import com.amazonaws.services.simpleworkflow.model.HistoryEvent;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecution;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionCompletedEventAttributes;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionContinuedAsNewEventAttributes;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionDetail;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionInfo;

/**
 * Convenience methods to be used by unit tests and during development.
 * 
 * @author fateev
 */
public class WorkflowExecutionUtils {

    /**
     * Blocks until workflow instance completes and returns its result. Useful
     * for unit tests and during development. Never use in
     * production setting as polling for worklow instance status is an expensive
     * operation.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * @return workflow instance result.
     * @throws InterruptedException
     *             if thread is interrupted
     * @throws RuntimeException
     *             if workflow instance ended up in any state but completed
     */
    public static WorkflowExecutionCompletedEventAttributes waitForWorkflowExecutionResult(AmazonSimpleWorkflow service,
            String domain, WorkflowExecution workflowExecution) throws InterruptedException {
        try {
            return waitForWorkflowExecutionResult(service, domain, workflowExecution, 0);
        }
        catch (TimeoutException e) {
            throw new Error("should never happen", e);
        }
    }

    /**
     * Waits up to specified timeout until workflow instance completes and
     * returns its result. Useful for unit tests and during development.
     * Never use in production setting as polling for worklow
     * instance status is an expensive operation.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * @return workflow instance result.
     * @throws InterruptedException
     *             if thread is interrupted
     * @throws TimeoutException
     *             if instance is not complete after specified timeout
     * @throws RuntimeException
     *             if workflow instance ended up in any state but completed
     */
    public static WorkflowExecutionCompletedEventAttributes waitForWorkflowExecutionResult(AmazonSimpleWorkflow service,
            String domain, WorkflowExecution workflowExecution, long timeoutSeconds)
            throws InterruptedException, TimeoutException {
        if (!waitForWorkflowInstanceCompletion(service, domain, workflowExecution, timeoutSeconds).equals(
                CloseStatus.COMPLETED.toString())) {
            String historyDump = WorkflowExecutionUtils.prettyPrintHistory(service, domain, workflowExecution);
            throw new RuntimeException("Workflow instance is not in completed state:\n" + historyDump);
        }
        return getWorkflowExecutionResult(service, domain, workflowExecution);
    }

    /**
     * Returns result of workflow instance execution. result of
     * {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * 
     * @throws IllegalStateException
     *             if workflow is still running
     * @throws RuntimeException
     *             if workflow instance ended up in any state but completed
     */
    public static WorkflowExecutionCompletedEventAttributes getWorkflowExecutionResult(AmazonSimpleWorkflow service,
            String domain, WorkflowExecution workflowExecution) {
        HistoryEvent closeEvent = getInstanceCloseEvent(service, domain, workflowExecution);
        if (closeEvent == null) {
            throw new IllegalStateException("Workflow is still running");
        }
        if (closeEvent.getEventType().equals(EventType.WorkflowExecutionCompleted.toString())) {
            return closeEvent.getWorkflowExecutionCompletedEventAttributes();
        }
        throw new RuntimeException("Workflow end state is not completed: " + prettyPrintHistoryEvent(closeEvent));
    }

    public static HistoryEvent getInstanceCloseEvent(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) {

        WorkflowExecutionInfo executionInfo = describeWorkflowInstance(service, domain, workflowExecution);
        if (executionInfo == null || executionInfo.getExecutionStatus().equals(ExecutionStatus.OPEN.toString())) {
            return null;
        }

        List events = getHistory(service, domain, workflowExecution);
        HistoryEvent result = null;
        for (HistoryEvent event : events) {
            if (isWorkflowExecutionCompletedEvent(event)) {
                result = event;
                break;
            }
        }
        return result;
    }

    public static boolean isWorkflowExecutionCompletedEvent(HistoryEvent event) {
        return ((event != null) && (event.getEventType().equals(EventType.WorkflowExecutionCompleted.toString())
                || event.getEventType().equals(EventType.WorkflowExecutionCanceled.toString())
                || event.getEventType().equals(EventType.WorkflowExecutionFailed.toString())
                || event.getEventType().equals(EventType.WorkflowExecutionTimedOut.toString())
                || event.getEventType().equals(EventType.WorkflowExecutionContinuedAsNew.toString()) || event.getEventType().equals(
                EventType.WorkflowExecutionTerminated.toString())));
    }

    public static boolean isActivityTaskClosedEvent(HistoryEvent event) {
        return ((event != null) && (event.getEventType().equals(EventType.ActivityTaskCompleted.toString())
                || event.getEventType().equals(EventType.ActivityTaskCanceled.toString())
                || event.getEventType().equals(EventType.ActivityTaskFailed.toString()) || event.getEventType().equals(
                EventType.ActivityTaskTimedOut.toString())));
    }

    public static boolean isExternalWorkflowClosedEvent(HistoryEvent event) {
        return ((event != null) && (event.getEventType().equals(EventType.ChildWorkflowExecutionCompleted.toString())
                || event.getEventType().equals(EventType.ChildWorkflowExecutionCanceled.toString())
                || event.getEventType().equals(EventType.ChildWorkflowExecutionFailed.toString())
                || event.getEventType().equals(EventType.ChildWorkflowExecutionTerminated.toString()) || event.getEventType().equals(
                EventType.ChildWorkflowExecutionTimedOut.toString())));
    }

    public static WorkflowExecution getWorkflowIdFromExternalWorkflowCompletedEvent(HistoryEvent event) {
        if (event != null) {
            if (event.getEventType().equals(EventType.ChildWorkflowExecutionCompleted.toString())) {
                return event.getChildWorkflowExecutionCompletedEventAttributes().getWorkflowExecution();
            }
            else if (event.getEventType().equals(EventType.ChildWorkflowExecutionCanceled.toString())) {
                return event.getChildWorkflowExecutionCanceledEventAttributes().getWorkflowExecution();
            }
            else if (event.getEventType().equals(EventType.ChildWorkflowExecutionFailed.toString())) {
                return event.getChildWorkflowExecutionFailedEventAttributes().getWorkflowExecution();
            }
            else if (event.getEventType().equals(EventType.ChildWorkflowExecutionTerminated.toString())) {
                return event.getChildWorkflowExecutionTerminatedEventAttributes().getWorkflowExecution();
            }
            else if (event.getEventType().equals(EventType.ChildWorkflowExecutionTimedOut.toString())) {
                return event.getChildWorkflowExecutionTimedOutEventAttributes().getWorkflowExecution();
            }
        }

        return null;
    }
    
    public static String getId(HistoryEvent historyEvent) {
        String id = null;
        if (historyEvent != null) {
            if (historyEvent.getEventType().equals(EventType.StartChildWorkflowExecutionFailed.toString())) {
                id = historyEvent.getStartChildWorkflowExecutionFailedEventAttributes().getWorkflowId();
            } else if (historyEvent.getEventType().equals(EventType.ScheduleActivityTaskFailed.toString())) {
                id = historyEvent.getScheduleActivityTaskFailedEventAttributes().getActivityId();
            } else if (historyEvent.getEventType().equals(EventType.StartTimerFailed.toString())) {
                id = historyEvent.getStartTimerFailedEventAttributes().getTimerId();
            } 
        }
        
        return id;
    }
    
    public static String getFailureCause(HistoryEvent historyEvent) {
        String failureCause = null;
        if (historyEvent != null) {
            if (historyEvent.getEventType().equals(EventType.StartChildWorkflowExecutionFailed.toString())) {
                failureCause = historyEvent.getStartChildWorkflowExecutionFailedEventAttributes().getCause();
            } else if (historyEvent.getEventType().equals(EventType.SignalExternalWorkflowExecutionFailed.toString())) {
                failureCause = historyEvent.getSignalExternalWorkflowExecutionFailedEventAttributes().getCause();
            } else if (historyEvent.getEventType().equals(EventType.ScheduleActivityTaskFailed.toString())) {
                failureCause = historyEvent.getScheduleActivityTaskFailedEventAttributes().getCause();
            } else if (historyEvent.getEventType().equals(EventType.StartTimerFailed.toString())) {
                failureCause = historyEvent.getStartTimerFailedEventAttributes().getCause();
            } else if (historyEvent.getEventType().equals(EventType.ContinueAsNewWorkflowExecutionFailed.toString())) {
                failureCause = historyEvent.getContinueAsNewWorkflowExecutionFailedEventAttributes().getCause();
            } else if (historyEvent.getEventType().equals(EventType.RecordMarkerFailed.toString())) {
            	failureCause = historyEvent.getRecordMarkerFailedEventAttributes().getCause();
            }
        }
        
        return failureCause;
    }

    /**
     * Blocks until workflow instance completes. Never use in
     * production setting as polling for worklow instance status is an expensive
     * operation.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * @return instance close status
     */
    public static String waitForWorkflowInstanceCompletion(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) throws InterruptedException {
        try {
            return waitForWorkflowInstanceCompletion(service, domain, workflowExecution, 0);
        }
        catch (TimeoutException e) {
            throw new Error("should never happen", e);
        }
    }

    /**
     * Waits up to specified timeout for workflow instance completion.
     * Never use in production setting as polling for worklow
     * instance status is an expensive operation.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * @param timeoutSeconds
     *            maximum time to wait for completion. 0 means wait forever.
     * @return instance close status
     * @throws TimeoutException
     */
    public static String waitForWorkflowInstanceCompletion(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution, long timeoutSeconds) 
                throws InterruptedException, TimeoutException {
        long start = System.currentTimeMillis();
        WorkflowExecutionInfo executionInfo = null;
        do {
            if (timeoutSeconds > 0 && System.currentTimeMillis() - start >= timeoutSeconds * 1000) {
                String historyDump = WorkflowExecutionUtils.prettyPrintHistory(service, domain, workflowExecution);
                throw new TimeoutException("Workflow instance is not complete after " + timeoutSeconds + " seconds: \n"
                        + historyDump);
            }
            if (executionInfo != null) {
                Thread.sleep(1000);
            }
            executionInfo = describeWorkflowInstance(service, domain, workflowExecution);
        }
        while (executionInfo.getExecutionStatus().equals(ExecutionStatus.OPEN.toString()));
        return executionInfo.getCloseStatus();
    }

    /**
     * Like
     * {@link #waitForWorkflowInstanceCompletion(AmazonSimpleWorkflow, String, WorkflowExecution, long)}
     * , except will wait for continued generations of the original workflow
     * execution too.
     * 
     * @param service
     * @param domain
     * @param workflowExecution
     * @param timeoutSeconds
     * @return
     * @throws InterruptedException
     * @throws TimeoutException
     * 
     * @see #waitForWorkflowInstanceCompletion(AmazonSimpleWorkflow, String,
     *      WorkflowExecution, long)
     */
    public static String waitForWorkflowInstanceCompletionAcrossGenerations(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution, long timeoutSeconds) throws InterruptedException, TimeoutException {

        WorkflowExecution lastExecutionToRun = workflowExecution;
        long millisecondsAtFirstWait = System.currentTimeMillis();
        String lastExecutionToRunCloseStatus = waitForWorkflowInstanceCompletion(service, domain, lastExecutionToRun,
                timeoutSeconds);

        // keep waiting if the instance continued as new
        while (lastExecutionToRunCloseStatus.equals(CloseStatus.CONTINUED_AS_NEW.toString())) {
            // get the new execution's information
            HistoryEvent closeEvent = getInstanceCloseEvent(service, domain, lastExecutionToRun);
            WorkflowExecutionContinuedAsNewEventAttributes continuedAsNewAttributes = closeEvent.getWorkflowExecutionContinuedAsNewEventAttributes();

            WorkflowExecution newGenerationExecution = new WorkflowExecution().withWorkflowId(lastExecutionToRun.getWorkflowId()).withRunId(
                    continuedAsNewAttributes.getNewExecutionRunId());
            
            // and wait for it
            long currentTime = System.currentTimeMillis();
            long millisecondsSinceFirstWait = currentTime - millisecondsAtFirstWait;
            long timeoutInSecondsForNextWait = timeoutSeconds - (millisecondsSinceFirstWait / 1000L);
            
            lastExecutionToRunCloseStatus = waitForWorkflowInstanceCompletion(service, domain, newGenerationExecution, timeoutInSecondsForNextWait);
            lastExecutionToRun = newGenerationExecution;
        }

        return lastExecutionToRunCloseStatus;
    }

    /**
     * Like
     * {@link #waitForWorkflowInstanceCompletionAcrossGenerations(AmazonSimpleWorkflow, String, WorkflowExecution, long)}
     * , but with no timeout.
     * 
     * @param service
     * @param domain
     * @param workflowExecution
     * @return
     * @throws InterruptedException
     */
    public static String waitForWorkflowInstanceCompletionAcrossGenerations(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) throws InterruptedException {
        try {
            return waitForWorkflowInstanceCompletionAcrossGenerations(service, domain, workflowExecution, 0L);
        }
        catch (TimeoutException e) {
            throw new Error("should never happen", e);
        }
    }

    public static WorkflowExecutionInfo describeWorkflowInstance(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) {
        DescribeWorkflowExecutionRequest describeRequest = new DescribeWorkflowExecutionRequest();
        describeRequest.setDomain(domain);
        describeRequest.setExecution(workflowExecution);
        WorkflowExecutionDetail executionDetail = service.describeWorkflowExecution(describeRequest);
        WorkflowExecutionInfo instanceMetadata = executionDetail.getExecutionInfo();
        return instanceMetadata;
    }

    /**
     * Returns workflow instance history in a human readable format.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     */
    public static String prettyPrintHistory(AmazonSimpleWorkflow service, String domain, WorkflowExecution workflowExecution) {
        return prettyPrintHistory(service, domain, workflowExecution, true);
    }

    /**
     * Returns workflow instance history in a human readable format.
     * 
     * @param workflowExecution
     *            result of
     *            {@link AmazonSimpleWorkflow#startWorkflowInstance(com.amazonaws.services.simpleworkflow.model.StartWorkflowInstanceRequest)}
     * @param showWorkflowTasks
     *            when set to false workflow task events (decider events) are
     *            not included
     */
    public static String prettyPrintHistory(AmazonSimpleWorkflow service, String domain, WorkflowExecution workflowExecution,
            boolean showWorkflowTasks) {
        List events = getHistory(service, domain, workflowExecution);
        return prettyPrintHistory(events, showWorkflowTasks);
    }

    public static List getHistory(AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) {
        List events = new ArrayList();
        String nextPageToken = null;
        do {
            History history = getHistoryPage(nextPageToken, service, domain, workflowExecution);
            events.addAll(history.getEvents());
            nextPageToken = history.getNextPageToken();
        }
        while (nextPageToken != null);
        return events;
    }

    public static History getHistoryPage(String nextPageToken, AmazonSimpleWorkflow service, String domain,
            WorkflowExecution workflowExecution) {

        GetWorkflowExecutionHistoryRequest getHistoryRequest = new GetWorkflowExecutionHistoryRequest();
        getHistoryRequest.setDomain(domain);
        getHistoryRequest.setExecution(workflowExecution);
        getHistoryRequest.setNextPageToken(nextPageToken);

        History history = service.getWorkflowExecutionHistory(getHistoryRequest);
        if (history == null) {
            throw new IllegalArgumentException("unknown workflow execution: " + workflowExecution);
        }
        return history;
    }

    /**
     * Returns workflow instance history in a human readable format.
     * 
     * @history Workflow instance history
     * @param showWorkflowTasks
     *            when set to false workflow task events (decider events) are
     *            not included
     */
    public static String prettyPrintHistory(History history, boolean showWorkflowTasks) {
        return prettyPrintHistory(history.getEvents(), showWorkflowTasks);
    }

    public static String prettyPrintHistory(Iterable events, boolean showWorkflowTasks) {
        StringBuffer result = new StringBuffer();
        result.append("{");
        boolean first = true;
        for (HistoryEvent event : events) {
            if (!showWorkflowTasks && event.getEventType().startsWith("WorkflowTask")) {
                continue;
            }
            if (first) {
                first = false;
            }
            else {
                result.append(",");
            }
            result.append("\n    ");
            result.append(prettyPrintHistoryEvent(event));
        }
        result.append("\n}");
        return result.toString();
    }

    public static String prettyPrintDecisions(Iterable decisions) {
        StringBuffer result = new StringBuffer();
        result.append("{");
        boolean first = true;
        for (Decision decision : decisions) {
            if (first) {
                first = false;
            }
            else {
                result.append(",");
            }
            result.append("\n    ");
            result.append(prettyPrintDecision(decision));
        }
        result.append("\n}");
        return result.toString();
    }

    /**
     * Returns single event in a human readable format
     * 
     * @param event
     *            event to pretty print
     */
    public static String prettyPrintHistoryEvent(HistoryEvent event) {
        String eventType = event.getEventType();
        StringBuffer result = new StringBuffer();
        result.append(eventType);
        result.append(prettyPrintObject(event, "getType", true, "    ", false));
        return result.toString();
    }

    /**
     * Returns single decision in a human readable format
     * 
     * @param event
     *            event to pretty print
     */
    public static String prettyPrintDecision(Decision decision) {
        return prettyPrintObject(decision, "getType", true, "    ", true);
    }
    
    /**
     * Not really a generic method for printing random object graphs. But it
     * works for events and decisions.
     */
    private static String prettyPrintObject(Object object, String methodToSkip, boolean skipNullsAndEmptyCollections,
            String indentation, boolean skipLevel) {
        StringBuffer result = new StringBuffer();
        if (object == null) {
            return "null";
        }
        Class clz = object.getClass();
        if (Number.class.isAssignableFrom(clz)) {
            return String.valueOf(object);
        }
        if (Boolean.class.isAssignableFrom(clz)) {
            return String.valueOf(object);
        }
        if (clz.equals(String.class)) {
            return (String) object;
        }
        if (clz.equals(Date.class)) {
            return String.valueOf(object);
        }
        if (Map.class.isAssignableFrom(clz)) {
            return String.valueOf(object);
        }
        if (Collection.class.isAssignableFrom(clz)) {
            return String.valueOf(object);
        }
        if (!skipLevel) {
            result.append(" {");
        }
        Method[] eventMethods = object.getClass().getMethods();
        boolean first = true;
        for (Method method : eventMethods) {
            String name = method.getName();
            if (!name.startsWith("get")) {
                continue;
            }
            if (name.equals(methodToSkip) || name.equals("getClass")) {
                continue;
            }
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }
            Object value;
            try {
                value = method.invoke(object, (Object[]) null);
                if (value != null && value.getClass().equals(String.class) && name.equals("getDetails")) {
                    value = printDetails((String) value);
                }
            }
            catch (InvocationTargetException e) {
                throw new RuntimeException(e.getTargetException());
            }
            catch (RuntimeException e) {
                throw (RuntimeException) e;
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (skipNullsAndEmptyCollections) {
                if (value == null) {
                    continue;
                }
                if (value instanceof Map && ((Map) value).isEmpty()) {
                    continue;
                }
                if (value instanceof Collection && ((Collection) value).isEmpty()) {
                    continue;
                }
            }
            if (!skipLevel) {
                if (first) {
                    first = false;
                }
                else {
                    result.append(";");
                }
                result.append("\n");
                result.append(indentation);
                result.append("    ");
                result.append(name.substring(3));
                result.append(" = ");
                result.append(prettyPrintObject(value, methodToSkip, skipNullsAndEmptyCollections, indentation + "    ", false));
            }
            else {
                result.append(prettyPrintObject(value, methodToSkip, skipNullsAndEmptyCollections, indentation, false));
            }
        }
        if (!skipLevel) {
            result.append("\n");
            result.append(indentation);
            result.append("}");
        }
        return result.toString();
    }
    
    public static String printDetails(String details) {
        Throwable failure = null;
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
            
            failure = mapper.readValue(details, Throwable.class);
        } catch (Exception e) {
            // eat up any data converter exceptions
        }
        
        if (failure != null) {
            StringBuilder builder = new StringBuilder();
            
            // Also print callstack
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            failure.printStackTrace(pw);
            
            builder.append(sw.toString());
            
            details = builder.toString();
        }
        
        return details;
    }

    /**
     * Simple Workflow limits length of the reason field. This method truncates
     * the passed argument to the maximum length.
     * 
     * @param reason
     *            string value to truncate
     * @return truncated value
     */
    public static String truncateReason(String reason) {
        if (reason != null && reason.length() > FlowValueConstraint.FAILURE_REASON.getMaxSize()) {
            reason = reason.substring(0, FlowValueConstraint.FAILURE_REASON.getMaxSize());
        }
        return reason;
    }
    
    public static String truncateDetails(String details) {
        if (details != null && details.length() > FlowValueConstraint.FAILURE_DETAILS.getMaxSize()) {
            details = details.substring(0, FlowValueConstraint.FAILURE_DETAILS.getMaxSize());
        }
        return details;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy