org.openecomp.sdnc.sli.SliPluginUtils.SliPluginUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.openecomp.sdnc.sli.SliPluginUtils.SliPluginUtils.java

Source

/*-
 * ============LICENSE_START=======================================================
 * openECOMP : SDN-C
 * ================================================================================
 * Copyright (C) 2017 AT&T Intellectual Property. 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.
 * 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.
 * ============LICENSE_END=========================================================
 */

package org.openecomp.sdnc.sli.SliPluginUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.openecomp.sdnc.sli.SvcLogicContext;
import org.openecomp.sdnc.sli.SvcLogicException;
import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A utility class used to streamline the interface between Java plugins,
 * the Service Logic Context, and Directed Graphs.
 * @version 7.0.1
 * @see org.openecomp.sdnc.sli.SvcLogicContext
 */
public class SliPluginUtils implements SvcLogicJavaPlugin {
    public enum LogLevel {
        TRACE, DEBUG, INFO, WARN, ERROR;
    }

    private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);

    // ========== CONSTRUCTORS ==========

    public SliPluginUtils() {
    }

    public SliPluginUtils(Properties props) {
    }

    // ========== CONTEXT MEMORY FUNCTIONS ==========

    /**
     * Removes 1 or more elements from a list in context memory.
     * <p>
     * Values are removed based on either the index in the list, a key-value
     * pair, or a list of key-value pairs that all must match in the element.
     * @param parameters
     * @param ctx Reference to context memory
     * @throws SvcLogicException All exceptions are wrapped in
     * SvcLogicException for compatibility with SLI.
     * @since 7.0.1
     */
    public void ctxListRemove(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        try {
            LOG.debug("ENTERING Execute Node \"ctxListRemove\"");

            // Validate, Log, & read parameters
            checkParameters(parameters, new String[] { "list_pfx" }, LOG);
            logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
            String list_pfx = parameters.get("list_pfx");
            String param_index = parameters.get("index");
            String param_key = parameters.get("key");
            String param_value = parameters.get("value");
            String param_keys_length = parameters.get("keys_length");

            // Initialize context memory list mimic
            SvcLogicContextList list;

            // Process based on input parameters:
            //   index: remove object at specific index
            //   key & value: remove all objects with key-value pair
            //   keys_length: remove all objects that match all key-value pairs
            //                in list
            if (param_index != null) {
                // Parse index
                LOG.trace("executing remove by index logic");
                int index;
                try {
                    index = Integer.parseInt(param_index);
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException(
                            "\"index\" parameter is not a number. index = " + param_index, e);
                }

                // Extract list from context memory & remove object @ index
                LOG.trace("extracting list from context memory");
                list = SvcLogicContextList.extract(ctx, list_pfx);
                LOG.trace("removing elements from list");
                list.remove(index);
            } else if (param_value != null) {
                if (param_key == null) {
                    param_key = "";
                }

                // Extract list from context memory & remove objects with
                // key-value pair
                LOG.trace("executing remove by key-value pair logic");
                LOG.trace("extracting list from context memory");
                list = SvcLogicContextList.extract(ctx, list_pfx);
                LOG.trace("removing elements from list");
                list.remove(param_key, param_value);
            } else if (param_keys_length != null) {
                // Parse keys_length
                LOG.trace("executing remove by key-value pair list logic");
                int keys_length;
                try {
                    keys_length = Integer.parseInt(param_keys_length);
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException(
                            "\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
                }

                // Obtain key-value pairs to check from parameters
                LOG.trace("reading keys parameter list");
                HashMap<String, String> keys_values = new HashMap<String, String>();
                for (int i = 0; i < keys_length; i++) {
                    keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
                }

                // Extract list from context memory & remove objects with all
                // key-value pairs matching
                LOG.trace("extracting list from context memory");
                list = SvcLogicContextList.extract(ctx, list_pfx);
                LOG.trace("removing elements from list");
                list.remove(keys_values);
            } else {
                throw new IllegalArgumentException(
                        "Required parameters missing. Requires one of: index, key & value, or keys_length array");
            }

            // Remove index from list
            LOG.trace("writing list back into context memory");
            list.writeToContext(ctx);
        } catch (Exception e) {
            throw new SvcLogicException("An error occurred in the ctxListRemove Execute node", e);
        } finally {
            LOG.debug("EXITING Execute Node \"ctxListRemove\"");
        }
    }

    /**
     * ctxSortList
     * @param parameters - the set of required parameters must contain list and delimiter.
     * @param ctx Reference to context memory
     * @throws SvcLogicException if a required parameter is missing an exception is thrown
     */
    public void ctxSortList(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        checkParameters(parameters, new String[] { "list", "delimiter" }, LOG);
        ArrayList<SortableCtxListElement> list = new ArrayList<SortableCtxListElement>();

        String[] sort_fields = null;
        if (parameters.containsKey("sort-fields")) {
            sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
        }

        String ctx_list_str = parameters.get("list");
        int listSz = getArrayLength(ctx, ctx_list_str);

        for (int i = 0; i < listSz; i++) {
            list.add(new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields));
        }
        Collections.sort(list);

        ctxBulkErase(ctx, ctx_list_str);
        int i = 0;
        for (SortableCtxListElement list_element : list) {
            for (Map.Entry<String, String> entry : list_element.child_elements.entrySet()) {
                if (sort_fields == null) {
                    ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
                } else {
                    ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
                }
            }
            i++;
        }
        // Reset list length (removed by ctxBulkErase above)
        ctx.setAttribute(ctx_list_str + "_length", "" + listSz);
    }

    /**
     * generates a UUID and writes it to context memory
     * @param parameters - ctx-destination is a required parameter
     * @param ctx Reference to context memory
     * @throws SvcLogicException thrown if a UUID cannot be generated or if ctx-destination is missing or null
     */
    public void generateUUID(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        checkParameters(parameters, new String[] { "ctx-destination" }, LOG);
        ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString());
    }

    /**
     * Provides substring functionality to Directed Graphs.
     * <p>
     * Calls either String.substring(String beginIndex) or
     * String.substring(String beginInded, String endIndex) if the end-index
     * is present or not.
     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
     * <table border="1">
     *    <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
     *    <tbody>
     *       <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
     *       <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
     *       <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
     *       <tr><td>end-index</td><td>Optional</td><td>Ending index to pass to Java substring function. If not included, String.substring(begin) will be called.</td></tr>
     *    </tbody>
     * </table>
     * @param ctx Reference to context memory
     * @throws SvcLogicException
     * @since 8.0.1
     * @see SliPluginUtils#substring(Map, SvcLogicContext)
     */
    @Deprecated
    public void substring(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        try {
            checkParameters(parameters, new String[] { "string", "begin-index", "result" }, LOG);
            final String string = parameters.get("string");
            final String result = parameters.get("result");
            final String begin = parameters.get("begin-index");
            final String end = parameters.get("end-index");

            if (StringUtils.isEmpty(end)) {
                ctx.setAttribute(result, string.substring(Integer.parseInt(begin)));
            } else {
                ctx.setAttribute(result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)));
            }
        } catch (Exception e) {
            throw new SvcLogicException("An error occurred while the Directed Graph was performing a substring", e);
        }
    }

    // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========

    /**
     * Throws an exception and writes an error to the log file if a required
     * parameters is not found in the parametersMap.
     * <p>
     * Use at the beginning of functions that can be called by Directed Graphs
     * and can take parameters to verify that all parameters have been provided
     * by the Directed Graph.
     * @param parametersMap parameters Map passed to this node
     * @param requiredParams Array of parameters required by the calling function
     * @param log Reference to Logger to log to
     * @throws SvcLogicException if a String in the requiredParams array is
     * not a key in parametersMap.
     * @since 1.0
     */
    public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log)
            throws SvcLogicException {
        if (requiredParams == null || requiredParams.length < 1) {
            log.debug("required parameters was empty, exiting early.");
            return;
        }
        if (parametersMap == null || parametersMap.keySet().size() < 1) {
            String errorMessage = "This method requires the parameters [" + StringUtils.join(requiredParams, ",")
                    + "], but no parameters were passed in.";
            log.error(errorMessage);
            throw new SvcLogicException(errorMessage);
        }

        for (String param : requiredParams) {
            if (!parametersMap.containsKey(param)) {
                String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
                log.error(errorMessage);
                log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
                throw new SvcLogicException(errorMessage);
            }
        }
    }

    /**
     * Removes all key-value pairs with keys that begin with pfx
     * @param ctx Reference to context memory
     * @param pfx Prefix of key-value pairs to remove
     * @since 1.0
     */
    public static final void ctxBulkErase(SvcLogicContext ctx, String pfx) {
        ArrayList<String> Keys = new ArrayList<String>(ctx.getAttributeKeySet());
        for (String key : Keys) {
            if (key.startsWith(pfx)) {
                ctx.setAttribute(pfx + key.substring(pfx.length()), null);
            }
        }
    }

    /**
     * Copies all context memory key-value pairs that start with src_pfx to
     * the keys that start with dest_pfx + suffix, where suffix is the result
     * of {@code key.substring(src_pfx.length())}.
     * <p>
     * Does NOT guarantee removal of all keys at the destination before
     * copying, but will overwrite any destination keys that have a
     * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
     * before copy to erase destination root before copying from source.
     * @param ctx Reference to context memory.
     * @param src_pfx Prefix of the keys to copy values from.
     * @param dest_pfx Prefix of the keys to copy values to.
     * @since 1.0
     */
    public static final void ctxBulkCopy(SvcLogicContext ctx, String src_pfx, String dest_pfx) {
        // Remove trailing period from dest_pfx
        if (dest_pfx.charAt(dest_pfx.length() - 1) == '.') {
            dest_pfx = dest_pfx.substring(0, dest_pfx.length() - 1);
        }

        // For each context key that begins with src_pfx, set the value of the
        // key dest_pfx + the suffix of the key to the key's value
        ArrayList<String> Keys = new ArrayList<String>(ctx.getAttributeKeySet());
        for (String key : Keys) {
            if (key.startsWith(src_pfx)) {
                // Get suffix (no leading period)
                String suffix = key.substring(src_pfx.length());
                if (suffix.charAt(0) == '.') {
                    suffix = suffix.substring(1);
                }

                // Set destination's value to key's value
                ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
            }
        }
    }

    /**
     * Creates and returns a {@code Map<String, String>} that is a subset of
     * context memory where all keys begin with the prefix.
     * @param ctx Reference to context memory.
     * @param prefix Returned map's keys should all begin with this value.
     * @return A {@code Map<String, String>} containing all the key-value pairs
     * in ctx whose key begins with prefix.
     */
    public static final Map<String, String> ctxGetBeginsWith(SvcLogicContext ctx, String prefix) {
        Map<String, String> prefixMap = new HashMap<String, String>();

        for (String key : ctx.getAttributeKeySet()) {
            if (key.startsWith(prefix)) {
                prefixMap.put(key, ctx.getAttribute(key));
            }
        }

        return prefixMap;
    }

    /**
     * Returns true if key's value in context memory is "" or if it doesn't
     * exist in context memory.
     * @param ctx Reference to context memory.
     * @param key Key to search for.
     * @return true if key's value in context memory is "" or if it doesn't
     * exist in context memory.
     * @since 1.0
     */
    public static final boolean ctxKeyEmpty(SvcLogicContext ctx, String key) {
        String value = ctx.getAttribute(key);
        return value == null || value.isEmpty();
    }

    /**
     * Adds all key-value pairs in the entries Map to context memory.
     * @param ctx Reference to context memory. Value's {@code toString()}
     * function is used to add it.
     * @param entries {@code Map<String, ?>} of key-value pairs to add to
     * context memory. Value's {@code toString()} function is used to add it.
     * @return Reference to context memory to be used for function chaining.
     */
    public static final SvcLogicContext ctxPutAll(SvcLogicContext ctx, Map<String, ?> entries) {
        for (Map.Entry<String, ?> entry : entries.entrySet()) {
            ctxSetAttribute(ctx, entry.getKey(), entry.getValue());
            //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
        }

        return ctx;
    }

    /**
     * Sets a key in context memory to the output of object's toString(). The
     * key is deleted from context memory if object is null.
     * @param ctx Reference to context memory.
     * @param key Key to set.
     * @param object Object whose toString() will be the value set
     */
    public static final void ctxSetAttribute(SvcLogicContext ctx, String key, Object object) {
        if (object == null) {
            ctx.setAttribute(key, null);
        } else {
            ctx.setAttribute(key, object.toString());
        }
    }

    /**
     * Sets a key in context memory to the output of object's toString().
     * <p>
     * The key is deleted from context memory if object is null. The key and
     * value set in context memory are logged to the Logger at the provided
     * logLevel level.
     * @param <O> Any Java object
     * @param ctx Reference to context memory.
     * @param key Key to set.
     * @param obj Object whose toString() will be the value set
     * @param LOG Logger to log to
     * @param logLevel level to log at in Logger
     */
    public static final <O extends Object> void ctxSetAttribute(SvcLogicContext ctx, String key, O obj, Logger LOG,
            LogLevel logLevel) {
        String value = Objects.toString(obj, null);
        ctx.setAttribute(key, value);
        if (logLevelIsEnabled(LOG, logLevel)) {
            if (value == null) {
                logMessageAtLevel(LOG, logLevel, "Deleting " + key);
            } else {
                logMessageAtLevel(LOG, logLevel, "Setting " + key + " = " + value);
            }
        }
    }

    /**
     * Utility function used to get an array's length from context memory.
     * Will return 0 if key doesn't exist in context memory or isn't numeric.
     * <p>
     * Use to obtain a context memory array length without having to worry
     * about throwing a NumberFormatException.
     * @param ctx Reference to context memory
     * @param key Key in context memory whose value is the array's length. If
     * the key doesn't end in "_length", then "_length is appended.
     * @param log Reference to Logger to log to
     * @return The array length or 0 if the key is not found in context memory.
     * @since 1.0
     */
    public static final int getArrayLength(SvcLogicContext ctx, String key) {
        return getArrayLength(ctx, key, null, null, null);
    }

    /**
     * Utility function used to get an array's length from context memory.
     * Will return 0 if key doesn't exist in context memory or isn't numeric
     * and print the provided log message to the configured log file.
     * <p>
     * Use to obtain a context memory array length without having to worry
     * about throwing a NumberFormatException.
     * @param ctx Reference to context memory.
     * @param key Key in context memory whose value is the array's length. If
     * the key doesn't end in "_length", then "_length is appended.
     * @param log Reference to Logger to log to. Doesn't log if null.
     * @param logLevel Logging level to log the message at if the context
     * memory key isn't found. Doesn't log if null.
     * @param log_message Message to log if the context memory key isn't found.
     * Doesn't log if null.
     * @return The array length or 0 if the key is not found in context memory.
     * @since 1.0
     */
    public static final int getArrayLength(SvcLogicContext ctx, String key, Logger log, LogLevel logLevel,
            String log_message) {
        String ctxKey = (key.endsWith("_length")) ? key : key + "_length";
        try {
            return Integer.parseInt(ctx.getAttribute(ctxKey));
        } catch (NumberFormatException e) {
            if (log != null && logLevel != null && log_message != null) {
                switch (logLevel) {
                case TRACE:
                    log.trace(log_message);
                case DEBUG:
                    log.debug(log_message);
                    break;
                case INFO:
                    log.info(log_message);
                    break;
                case WARN:
                    log.warn(log_message);
                    break;
                case ERROR:
                    log.error(log_message);
                    break;
                }
            }
        }

        return 0;
    }

    /**
     * Prints sorted context memory key-value pairs to the log file at the log
     * level. Returns immediately if the log level isn't enabled.
     * <p>
     * O(n log(n)) time where n = size of context memory
     * @param ctx Reference to context memory
     * @param log Reference to Logger to log to
     * @param logLevel Logging level to log the context memory key-value pairs
     * at.
     * @since 1.0
     */
    public static final void logContextMemory(SvcLogicContext ctx, Logger log, LogLevel logLevel) {
        logLevelIsEnabled(log, logLevel);

        // Print sorted context memory key-value pairs to the log
        ArrayList<String> keys = new ArrayList<String>(ctx.getAttributeKeySet());
        Collections.sort(keys);
        for (String key : keys) {
            logMessageAtLevel(log, logLevel, key + " = " + ctx.getAttribute(key));
        }
    }

    // ========== PRIVATE FUNCTIONS ==========

    // TODO: javadoc
    /**
     *
     * @param parameters
     * @param log
     * @param loglevel
     * @since 7.0.1
     */
    public static final void logExecuteNodeParameters(Map<String, String> parameters, Logger log,
            LogLevel loglevel) {
        logLevelIsEnabled(log, loglevel);

        for (Map.Entry<String, String> param : parameters.entrySet()) {
            logMessageAtLevel(log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue());
        }
    }

    // TODO: javadoc
    /**
     * Returns true if the loglevel is enabled. Otherwise, returns false.
     * @param log Reference to logger
     * @param loglevel Log level to check if enabled
     * @return True if the loglevel is enabled. Otherwise, false
     * @since 7.0.1
     */
    private static final boolean logLevelIsEnabled(Logger log, LogLevel loglevel) {
        // Return immediately if logging level isn't enabled
        switch (loglevel) {
        case TRACE:
            if (log.isTraceEnabled()) {
                return true;
            }
            return false;
        case DEBUG:
            if (log.isDebugEnabled()) {
                return true;
            }
            return false;
        case INFO:
            if (log.isInfoEnabled()) {
                return true;
            }
            return false;
        case WARN:
            if (log.isWarnEnabled()) {
                return true;
            }
            return false;
        case ERROR:
            if (log.isErrorEnabled()) {
                return true;
            }
            return false;
        default:
            throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
        }
    }

    // TODO: javadoc
    /**
     *
     * @param log
     * @param loglevel
     * @param msg
     * @since 7.0.1
     */
    private static final void logMessageAtLevel(Logger log, LogLevel loglevel, String msg) {
        switch (loglevel) {
        case TRACE:
            log.trace(msg);
            return;
        case DEBUG:
            log.debug(msg);
            return;
        case INFO:
            log.info(msg);
            return;
        case WARN:
            log.warn(msg);
            return;
        case ERROR:
            log.error(msg);
            return;
        }
    }

    // ========== LOCAL CLASSES ==========

    private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
        HashMap<String, String> child_elements = new HashMap<String, String>();
        String[] sort_fields;

        public SortableCtxListElement(SvcLogicContext ctx, String root, String[] sort_fields) {
            this.sort_fields = sort_fields;

            for (String key : ctx.getAttributeKeySet()) {
                if (key.startsWith(root)) {
                    if (key.length() == root.length()) {
                        child_elements.put("", ctx.getAttribute(key));
                        break;
                    } else {
                        child_elements.put(key.substring(root.length() + 1), ctx.getAttribute(key));
                    }
                }
            }
        }

        @Override
        public int compareTo(SortableCtxListElement arg0) {
            if (sort_fields == null) {
                return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
            }

            for (String field : this.sort_fields) {
                int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
                if (result != 0) {
                    return result;
                }
            }

            return 0;
        }
    }

    /**
      * Creates a file that contains the content of context memory.
      * @param parameters - must contain the parameter filename
      * @param ctx Reference to context memory
      * @throws SvcLogicException thrown if file cannot be created or if parameters are missing
      */
    public static void printContext(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        if (parameters == null || parameters.isEmpty()) {
            throw new SvcLogicException("no parameters passed");
        }

        checkParameters(parameters, new String[] { "filename" }, LOG);

        String fileName = parameters.get("filename");

        try (FileOutputStream fstr = new FileOutputStream(new File(fileName));
                PrintStream pstr = new PrintStream(fstr, true);) {
            pstr.println("#######################################");
            for (String attr : ctx.getAttributeKeySet()) {
                pstr.println(attr + " = " + ctx.getAttribute(attr));
            }
        } catch (Exception e) {
            throw new SvcLogicException("Cannot write context to file " + fileName, e);
        }

    }

    /**
     * Checks context memory for a set of required parameters
     * Every parameter aside from prefix will be treated as mandatory
     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
     * <table border="1">
     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
     *  <tbody>
     *      <tr><td>prefix</td><td>Optional</td><td>the prefix will be added to each parameter</td></tr>
     *  </tbody>
     * </table>
     * @param ctx Reference to context memory
     * @throws SvcLogicException
     * @since 11.0.2
     */
    public static void requiredParameters(Map<String, String> parameters, SvcLogicContext ctx)
            throws SvcLogicException {
        if (parameters == null || parameters.keySet().size() < 1) {
            String errorMessage = "requiredParameters should not be called if the parameters hashmap is null or empty!";
            LOG.error(errorMessage);
            throw new SvcLogicException(errorMessage);
        }
        String prefixValue = null;
        String prefix = "prefix";
        if (parameters.containsKey(prefix)) {
            prefixValue = parameters.get(prefix);
            parameters.remove(prefix);
        }
        checkParameters(prefixValue, ctx.getAttributeKeySet(), parameters.keySet(), LOG);
    }

    private static void checkParameters(String prefixValue, Set<String> ctx, Set<String> parameters, Logger log)
            throws SvcLogicException {
        for (String param : parameters) {
            if (prefixValue != null) {
                param = prefixValue + param;
            }
            if (!ctx.contains(param)) {
                String errorMessage = "This method requires the parameters [" + StringUtils.join(parameters, ",")
                        + "], but " + param + " was not passed in.";
                log.error(errorMessage);
                throw new SvcLogicException(errorMessage);
            }
        }
    }

    /**
     *  is in a different DG invocation just before/after we call NCS and set the state to InProgress
     */
    /**
    * setTime write the current date time to a string located at outputPath
    * @param parameters - requires outputPath to not be null
    * @param ctx Reference to context memory
    * @throws SvcLogicException if a required parameter is missing an exception is thrown
    */
    public static void setTime(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
        checkParameters(parameters, new String[] { "outputPath" }, LOG);

        // Set the DateFormat
        // "2015-03-16T12:18:35.138Z"
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

        // Parse the date
        String ctxVariable = parameters.get("outputPath");
        try {
            String dateTime = format.format(new Date());
            ctx.setAttribute(ctxVariable, dateTime);
        } catch (Exception ex) {
            throw new SvcLogicException("problem with setTime", ex);
        }
    }
}