2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
7 * ================================================================================
8 * Modifications Copyright (C) 2018 IBM.
9 * ================================================================================
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.ccsdk.sli.core.slipluginutils;
27 import java.io.FileOutputStream;
28 import java.io.PrintStream;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.Date;
34 import java.util.HashMap;
35 import java.util.HashSet;
37 import java.util.Map.Entry;
38 import java.util.Objects;
39 import java.util.Properties;
41 import java.util.UUID;
42 import org.apache.commons.lang3.StringUtils;
43 import org.apache.commons.text.StringEscapeUtils;
44 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
45 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
46 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import com.google.gson.JsonArray;
50 import com.google.gson.JsonElement;
51 import com.google.gson.JsonObject;
52 import com.google.gson.JsonParser;
55 * A utility class used to streamline the interface between Java plugins,
56 * the Service Logic Context, and Directed Graphs.
58 * @see org.onap.ccsdk.sli.core.sli.SvcLogicContext
60 public class SliPluginUtils implements SvcLogicJavaPlugin {
61 public enum LogLevel {
62 TRACE, DEBUG, INFO, WARN, ERROR;
65 private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);
66 private static final String LOG_MSG="extracting list from context memory";
67 private static final String LOG_MSG1="removing elements from list";
68 private static final String LENGTH="_length";
71 // ========== CONSTRUCTORS ==========
73 public SliPluginUtils() {}
75 public SliPluginUtils( Properties props ) {}
78 // ========== CONTEXT MEMORY FUNCTIONS ==========
81 * Removes 1 or more elements from a list in context memory.
83 * Values are removed based on either the index in the list, a key-value
84 * pair, or a list of key-value pairs that all must match in the element.
86 * @param ctx Reference to context memory
87 * @throws SvcLogicException All exceptions are wrapped in
88 * SvcLogicException for compatibility with SLI.
91 public void ctxListRemove( Map<String,String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
93 LOG.debug( "ENTERING Execute Node \"ctxListRemove\"" );
95 // Validate, Log, & read parameters
96 checkParameters(parameters, new String[]{"list_pfx"}, LOG);
97 logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
98 String list_pfx = parameters.get("list_pfx");
99 String param_index = parameters.get("index");
100 String param_key = parameters.get("key");
101 String param_value = parameters.get("value");
102 String param_keys_length = parameters.get("keys_length");
104 // Initialize context memory list mimic
105 SvcLogicContextList list;
107 // Process based on input parameters:
108 // index: remove object at specific index
109 // key & value: remove all objects with key-value pair
110 // keys_length: remove all objects that match all key-value pairs
112 if( param_index != null ) {
114 LOG.trace("executing remove by index logic");
117 index = Integer.parseInt(param_index);
119 catch( NumberFormatException e ) {
120 throw new IllegalArgumentException("\"index\" parameter is not a number. index = " + param_index, e);
123 // Extract list from context memory & remove object @ index
125 list = SvcLogicContextList.extract(ctx, list_pfx);
129 else if( param_value != null ) {
130 if( param_key == null ) { param_key = ""; }
132 // Extract list from context memory & remove objects with
134 LOG.trace("executing remove by key-value pair logic");
136 list = SvcLogicContextList.extract(ctx, list_pfx);
138 list.remove( param_key, param_value );
140 else if( param_keys_length != null ) {
142 LOG.trace("executing remove by key-value pair list logic");
145 keys_length = Integer.parseInt(param_keys_length);
147 catch( NumberFormatException e ) {
148 throw new IllegalArgumentException("\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
151 // Obtain key-value pairs to check from parameters
152 LOG.trace("reading keys parameter list");
153 HashMap<String,String> keys_values = new HashMap<>();
154 for( int i = 0; i < keys_length; i++ ) {
155 keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
158 // Extract list from context memory & remove objects with all
159 // key-value pairs matching
161 list = SvcLogicContextList.extract(ctx, list_pfx);
163 list.remove(keys_values);
166 throw new IllegalArgumentException("Required parameters missing. Requires one of: index, key & value, or keys_length array");
169 // Remove index from list
170 LOG.trace("writing list back into context memory");
171 list.writeToContext(ctx);
173 catch( Exception e ) {
174 throw new SvcLogicException( "An error occurred in the ctxListRemove Execute node", e );
177 LOG.debug( "EXITING Execute Node \"ctxListRemove\"" );
183 * @param parameters - the set of required parameters must contain list and delimiter.
184 * @param ctx Reference to context memory
185 * @throws SvcLogicException if a required parameter is missing an exception is thrown
187 public void ctxSortList( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
188 checkParameters(parameters, new String[]{"list","delimiter"}, LOG);
189 ArrayList<SortableCtxListElement> list = new ArrayList<>();
191 String[] sort_fields = null;
192 if( parameters.containsKey("sort-fields") ) {
193 sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
196 String ctx_list_str = parameters.get("list");
197 int listSz = getArrayLength(ctx, ctx_list_str);
201 for( int i = 0; i < listSz; i++ ) {
202 list.add( new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields) );
204 Collections.sort(list);
206 ctxBulkErase(ctx, ctx_list_str);
208 for( SortableCtxListElement list_element : list ) {
209 for( Map.Entry<String,String> entry : list_element.child_elements.entrySet() ) {
210 if( sort_fields == null ) {
211 ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
214 ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
219 // Reset list length (removed by ctxBulkErase above)
220 ctx.setAttribute(ctx_list_str+LENGTH, Integer.toString(listSz));
224 * generates a UUID and writes it to context memory
225 * @param parameters - ctx-destination is a required parameter
226 * @param ctx Reference to context memory
227 * @throws SvcLogicException thrown if a UUID cannot be generated or if ctx-destination is missing or null
229 public void generateUUID( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
230 checkParameters(parameters, new String[]{"ctx-destination"}, LOG);
231 ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString() );
235 * Provides substring functionality to Directed Graphs.
237 * Calls either String.substring(String beginIndex) or
238 * String.substring(String beginInded, String endIndex) if the end-index
240 * @param parameters HashMap<String,String> of parameters passed by the DG to this function
242 * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
244 * <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
245 * <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
246 * <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
247 * <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>
250 * @param ctx Reference to context memory
251 * @throws SvcLogicException
253 * @see SliPluginUtils#substring(Map, SvcLogicContext)
256 public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
258 checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
259 final String string = parameters.get("string");
260 final String result = parameters.get("result");
261 final String begin = parameters.get("begin-index");
262 final String end = parameters.get("end-index");
264 if( StringUtils.isEmpty(end) ) {
265 ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
268 ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
271 catch( Exception e ) {
272 throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
278 // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========
281 * Throws an exception and writes an error to the log file if a required
282 * parameters is not found in the parametersMap.
284 * Use at the beginning of functions that can be called by Directed Graphs
285 * and can take parameters to verify that all parameters have been provided
286 * by the Directed Graph.
287 * @param parametersMap parameters Map passed to this node
288 * @param requiredParams Array of parameters required by the calling function
289 * @param log Reference to Logger to log to
290 * @throws SvcLogicException if a String in the requiredParams array is
291 * not a key in parametersMap.
294 public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log) throws SvcLogicException {
295 if( requiredParams == null || requiredParams.length < 1){
296 log.debug("required parameters was empty, exiting early.");
299 if (parametersMap == null || parametersMap.keySet().isEmpty()){
300 String errorMessage = "This method requires the parameters [" + StringUtils.join(requiredParams,",") + "], but no parameters were passed in.";
301 log.error(errorMessage);
302 throw new SvcLogicException(errorMessage);
305 for (String param : requiredParams) {
306 if (!parametersMap.containsKey(param)) {
307 String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
308 log.error(errorMessage);
309 log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
310 throw new SvcLogicException(errorMessage);
316 * Removes all key-value pairs with keys that begin with pfx
317 * @param ctx Reference to context memory
318 * @param pfx Prefix of key-value pairs to remove
321 public static final void ctxBulkErase( SvcLogicContext ctx, String pfx ) {
322 ArrayList<String> Keys = new ArrayList<>(ctx.getAttributeKeySet());
323 for( String key : Keys ) {
324 if( key.startsWith( pfx ) ) {
325 ctx.setAttribute( pfx + key.substring(pfx.length()) , null);
331 * Copies all context memory key-value pairs that start with src_pfx to
332 * the keys that start with dest_pfx + suffix, where suffix is the result
333 * of {@code key.substring(src_pfx.length())}.
335 * Does NOT guarantee removal of all keys at the destination before
336 * copying, but will overwrite any destination keys that have a
337 * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
338 * before copy to erase destination root before copying from source.
339 * @param ctx Reference to context memory.
340 * @param src_pfx Prefix of the keys to copy values from.
341 * @param dest_pfx Prefix of the keys to copy values to.
344 public static final void ctxBulkCopy( SvcLogicContext ctx, String src_pfx, String dest_pfx ) {
345 // Remove trailing period from dest_pfx
346 if( dest_pfx.charAt(dest_pfx.length()-1) == '.' ) {
347 dest_pfx = dest_pfx.substring(0,dest_pfx.length()-1);
350 // For each context key that begins with src_pfx, set the value of the
351 // key dest_pfx + the suffix of the key to the key's value
352 ArrayList<String> Keys = new ArrayList<>(ctx.getAttributeKeySet());
353 for( String key : Keys ) {
354 if( key.startsWith(src_pfx) ) {
355 // Get suffix (no leading period)
356 String suffix = key.substring(src_pfx.length());
357 if( suffix.charAt(0) == '.') {
358 suffix = suffix.substring(1);
361 // Set destination's value to key's value
362 ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
368 * Creates and returns a {@code Map<String, String>} that is a subset of
369 * context memory where all keys begin with the prefix.
370 * @param ctx Reference to context memory.
371 * @param prefix Returned map's keys should all begin with this value.
372 * @return A {@code Map<String, String>} containing all the key-value pairs
373 * in ctx whose key begins with prefix.
375 public static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
376 Map<String, String> prefixMap = new HashMap<>();
378 for( String key : ctx.getAttributeKeySet() ) {
379 if( key.startsWith(prefix) ) {
380 prefixMap.put( key, ctx.getAttribute(key) );
388 * Returns true if key's value in context memory is "" or if it doesn't
389 * exist in context memory.
390 * @param ctx Reference to context memory.
391 * @param key Key to search for.
392 * @return true if key's value in context memory is "" or if it doesn't
393 * exist in context memory.
396 public static final boolean ctxKeyEmpty( SvcLogicContext ctx, String key ) {
397 String value = ctx.getAttribute(key);
398 return value == null || value.isEmpty();
402 * Adds all key-value pairs in the entries Map to context memory.
403 * @param ctx Reference to context memory. Value's {@code toString()}
404 * function is used to add it.
405 * @param entries {@code Map<String, ?>} of key-value pairs to add to
406 * context memory. Value's {@code toString()} function is used to add it.
407 * @return Reference to context memory to be used for function chaining.
409 public static final SvcLogicContext ctxPutAll( SvcLogicContext ctx, Map<String, ?> entries ) {
410 for( Map.Entry<String, ?> entry : entries.entrySet() ) {
411 ctxSetAttribute( ctx, entry.getKey(), entry.getValue() );
412 //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
419 * Sets a key in context memory to the output of object's toString(). The
420 * key is deleted from context memory if object is null.
421 * @param ctx Reference to context memory.
422 * @param key Key to set.
423 * @param object Object whose toString() will be the value set
425 public static final void ctxSetAttribute( SvcLogicContext ctx, String key, Object object ) {
426 if( object == null ) {
427 ctx.setAttribute(key, null);
430 ctx.setAttribute(key, object.toString());
435 * Sets a key in context memory to the output of object's toString().
437 * The key is deleted from context memory if object is null. The key and
438 * value set in context memory are logged to the Logger at the provided
440 * @param <O> Any Java object
441 * @param ctx Reference to context memory.
442 * @param key Key to set.
443 * @param obj Object whose toString() will be the value set
444 * @param LOG Logger to log to
445 * @param logLevel level to log at in Logger
447 public static final <O extends Object> void ctxSetAttribute( SvcLogicContext ctx, String key, O obj, Logger LOG, LogLevel logLevel ) {
448 String value = Objects.toString( obj, null );
449 ctx.setAttribute( key, value );
450 if( logLevelIsEnabled(LOG, logLevel ) ) {
451 if( value == null ) {
452 logMessageAtLevel( LOG, logLevel, "Deleting " + key );
455 logMessageAtLevel( LOG, logLevel, "Setting " + key + " = " + value );
461 * Utility function used to get an array's length from context memory.
462 * Will return 0 if key doesn't exist in context memory or isn't numeric.
464 * Use to obtain a context memory array length without having to worry
465 * about throwing a NumberFormatException.
466 * @param ctx Reference to context memory
467 * @param key Key in context memory whose value is the array's length. If
468 * the key doesn't end in "_length", then "_length is appended.
469 * @param log Reference to Logger to log to
470 * @return The array length or 0 if the key is not found in context memory.
473 public static final int getArrayLength( SvcLogicContext ctx, String key ) {
474 return getArrayLength(ctx, key, null, null, null);
478 * Utility function used to get an array's length from context memory.
479 * Will return 0 if key doesn't exist in context memory or isn't numeric
480 * and print the provided log message to the configured log file.
482 * Use to obtain a context memory array length without having to worry
483 * about throwing a NumberFormatException.
484 * @param ctx Reference to context memory.
485 * @param key Key in context memory whose value is the array's length. If
486 * the key doesn't end in "_length", then "_length is appended.
487 * @param log Reference to Logger to log to. Doesn't log if null.
488 * @param logLevel Logging level to log the message at if the context
489 * memory key isn't found. Doesn't log if null.
490 * @param log_message Message to log if the context memory key isn't found.
491 * Doesn't log if null.
492 * @return The array length or 0 if the key is not found in context memory.
495 public static final int getArrayLength( SvcLogicContext ctx, String key, Logger log, LogLevel logLevel, String log_message ) {
496 String ctxKey = key.endsWith(LENGTH) ? key : key + LENGTH;
498 return Integer.parseInt(ctx.getAttribute(ctxKey));
500 catch( NumberFormatException e ) {
501 if( log != null && logLevel != null && log_message != null ) {
504 log.trace(log_message);
507 log.debug(log_message);
510 log.info(log_message);
513 log.warn(log_message);
516 log.error(log_message);
526 * Prints sorted context memory key-value pairs to the log file at the log
527 * level. Returns immediately if the log level isn't enabled.
529 * O(n log(n)) time where n = size of context memory
530 * @param ctx Reference to context memory
531 * @param log Reference to Logger to log to
532 * @param logLevel Logging level to log the context memory key-value pairs
536 public static final void logContextMemory( SvcLogicContext ctx, Logger log, LogLevel logLevel ) {
537 logLevelIsEnabled( log, logLevel );
539 // Print sorted context memory key-value pairs to the log
540 ArrayList<String> keys = new ArrayList<>(ctx.getAttributeKeySet());
541 Collections.sort(keys);
542 for( String key : keys ) {
543 logMessageAtLevel( log, logLevel, key + " = " + ctx.getAttribute(key) );
549 // ========== PRIVATE FUNCTIONS ==========
559 public static final void logExecuteNodeParameters( Map<String,String> parameters, Logger log, LogLevel loglevel ) {
560 logLevelIsEnabled( log, loglevel );
562 for( Map.Entry<String,String> param : parameters.entrySet() ) {
563 logMessageAtLevel( log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue() );
569 * Returns true if the loglevel is enabled. Otherwise, returns false.
570 * @param log Reference to logger
571 * @param loglevel Log level to check if enabled
572 * @return True if the loglevel is enabled. Otherwise, false
575 private static final boolean logLevelIsEnabled( Logger log, LogLevel loglevel ) {
576 // Return immediately if logging level isn't enabled
579 if( log.isTraceEnabled() ) { return true; }
582 if( log.isDebugEnabled() ) { return true; }
585 if( log.isInfoEnabled() ) { return true; }
588 if( log.isWarnEnabled() ) { return true; }
591 if( log.isErrorEnabled() ) { return true; }
594 throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
606 private static final void logMessageAtLevel( Logger log, LogLevel loglevel, String msg ) {
628 // ========== LOCAL CLASSES ==========
630 private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
631 HashMap<String,String> child_elements = new HashMap<>();
632 String[] sort_fields;
634 public SortableCtxListElement( SvcLogicContext ctx, String root, String[] sort_fields ) {
635 this.sort_fields = sort_fields;
637 for( String key : ctx.getAttributeKeySet() ) {
638 if( key.startsWith(root) ) {
639 if( key.length() == root.length() ) {
640 child_elements.put("", ctx.getAttribute(key));
644 child_elements.put(key.substring(root.length()+1), ctx.getAttribute(key));
651 public int compareTo(SortableCtxListElement arg0) {
652 if( sort_fields == null ) {
653 return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
656 for( String field : this.sort_fields ) {
657 int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
667 public boolean equals(Object object) {
668 if (this == object) {
671 if (!(object instanceof SortableCtxListElement)) {
674 if (!super.equals(object)) {
678 SortableCtxListElement that = (SortableCtxListElement) object;
680 if (child_elements != null ? !child_elements.equals(that.child_elements)
681 : that.child_elements != null) {
684 // Probably incorrect - comparing Object[] arrays with Arrays.equals
685 if (!Arrays.equals(sort_fields, that.sort_fields)) {
693 public int hashCode() {
694 int result = super.hashCode();
695 result = 31 * result + (child_elements != null ? child_elements.hashCode() : 0);
696 result = 31 * result + Arrays.hashCode(sort_fields);
702 * Creates a file that contains the content of context memory.
703 * @param parameters - must contain the parameter filename
704 * @param ctx Reference to context memory
705 * @throws SvcLogicException thrown if file cannot be created or if parameters are missing
707 public static void printContext(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
708 if (parameters == null || parameters.isEmpty()) {
709 throw new SvcLogicException("no parameters passed");
712 checkParameters(parameters, new String[]{"filename"}, LOG);
714 String fileName = parameters.get("filename");
717 try (FileOutputStream fstr = new FileOutputStream(new File(fileName));
718 PrintStream pstr = new PrintStream(fstr, true);)
720 pstr.println("#######################################");
721 for (String attr : ctx.getAttributeKeySet()) {
722 pstr.println(attr + " = " + ctx.getAttribute(attr));
724 } catch (Exception e) {
725 throw new SvcLogicException("Cannot write context to file " + fileName, e);
732 * Checks context memory for a set of required parameters
733 * Every parameter aside from prefix will be treated as mandatory
734 * @param parameters HashMap<String,String> of parameters passed by the DG to this function
736 * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
738 * <tr><td>prefix</td><td>Optional</td><td>the prefix will be added to each parameter</td></tr>
741 * @param ctx Reference to context memory
742 * @throws SvcLogicException
745 public static void requiredParameters(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
746 if (parameters == null || parameters.keySet().isEmpty()) {
747 String errorMessage = "requiredParameters should not be called if the parameters hashmap is null or empty!";
748 LOG.error(errorMessage);
749 throw new SvcLogicException(errorMessage);
751 String prefixValue = null;
752 String prefix = "prefix";
753 if(parameters.containsKey(prefix)){
754 prefixValue = parameters.get(prefix);
755 parameters.remove(prefix);
757 checkParameters(prefixValue, ctx.getAttributeKeySet(), parameters.keySet(), LOG);
760 private static void checkParameters(String prefixValue, Set<String> ctx, Set<String> parameters, Logger log) throws SvcLogicException {
761 for (String param : parameters) {
762 if (prefixValue != null) {
763 param = prefixValue + param;
765 if (!ctx.contains(param)) {
766 String errorMessage = "This method requires the parameters [" + StringUtils.join(parameters, ",")
767 + "], but " + param + " was not passed in.";
768 log.error(errorMessage);
769 throw new SvcLogicException(errorMessage);
775 * is in a different DG invocation just before/after we call NCS and set the state to InProgress
778 * setTime write the current date time to a string located at outputPath
779 * @param parameters - requires outputPath to not be null
780 * @param ctx Reference to context memory
781 * @throws SvcLogicException if a required parameter is missing an exception is thrown
783 public static void setTime(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException
785 checkParameters(parameters, new String[] { "outputPath" }, LOG);
787 // Set the DateFormat
788 // "2015-03-16T12:18:35.138Z"
789 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
792 String ctxVariable = parameters.get("outputPath");
794 String dateTime = format.format(new Date());
795 ctx.setAttribute(ctxVariable, dateTime);
796 } catch (Exception ex) {
797 throw new SvcLogicException("problem with setTime", ex);
802 * jsonStringToCtx takes a json string stored as a single property in context memory and breaks it into individual properties
803 * @param parameters - requires source, outputPath and isEscaped to not be null.
804 * @param ctx Reference to context memory
805 * @throws SvcLogicException if a required parameter is missing an exception is thrown
807 public static void jsonStringToCtx(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException
809 checkParameters(parameters, new String[] { "source","outputPath","isEscaped" }, LOG);
811 String source = ctx.getAttribute(parameters.get("source"));
812 if("true".equals(parameters.get("isEscaped"))){
813 source = StringEscapeUtils.unescapeJson(source);
815 writeJsonToCtx(source, ctx,parameters.get("outputPath"));
816 } catch (Exception ex) {
817 throw new SvcLogicException("problem with jsonStringToCtx", ex);
821 protected static void writeJsonToCtx(String resp, SvcLogicContext ctx, String prefix){
822 JsonParser jp = new JsonParser();
823 JsonElement element = jp.parse(resp);
824 String root = prefix + ".";
825 if (element.isJsonObject()) {
826 writeJsonObject(element.getAsJsonObject(), ctx, root);
827 } else if (element.isJsonArray()) {
828 handleJsonArray("", element.getAsJsonArray(), ctx, root);
832 protected static void writeJsonObject(JsonObject obj, SvcLogicContext ctx, String root) {
833 for (Entry<String, JsonElement> entry : obj.entrySet()) {
834 String key = entry.getKey();
835 if (entry.getValue().isJsonObject()) {
836 writeJsonObject(entry.getValue().getAsJsonObject(), ctx, root + key + ".");
837 } else if (entry.getValue().isJsonArray()) {
838 JsonArray array = entry.getValue().getAsJsonArray();
839 handleJsonArray(key, array, ctx, root);
841 //Handles when a JSON obj is nested within a JSON obj
842 if(!root.endsWith(".")){
845 ctx.setAttribute(root + key, entry.getValue().getAsString());
850 protected static void handleJsonArray(String key, JsonArray array, SvcLogicContext ctx, String root) {
851 ctx.setAttribute(root + key + LENGTH, String.valueOf(array.size()));
852 Integer arrayIdx = 0;
853 for (JsonElement element : array) {
854 String prefix = root + key + "[" + arrayIdx + "]";
856 if (element.isJsonArray()) {
857 handleJsonArray(key, element.getAsJsonArray(), ctx, prefix);
858 } else if (element.isJsonObject()) {
859 writeJsonObject(element.getAsJsonObject(), ctx, prefix + ".");
860 } else if (element.isJsonPrimitive()) {
861 ctx.setAttribute(prefix, element.getAsString());
868 * getAttributeValue takes a ctx memory path as a string, gets the value stored at this path and set this value in context memory at
870 * @param parameters - requires source and outputPath
871 * @param ctx Reference to context memory
872 * @throws SvcLogicException if a required parameter is missing an exception is thrown
874 public static void getAttributeValue(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
875 checkParameters(parameters, new String[] { "source", "outputPath" }, LOG);
876 String source = ctx.getAttribute(parameters.get("source"));
877 ctx.setAttribute(parameters.get("outputPath"), source);
881 * ctxListContains provides a way to see if a context memory list contains a key value
882 * @param parameters - requires list, keyName, keyValue, outputPath to all not be null.
883 * @param ctx Reference to context memory
884 * @throws SvcLogicException if a required parameter is missing an exception is thrown
886 public static String ctxListContains(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
887 checkParameters(parameters, new String[]{"list", "keyName", "keyValue"}, LOG);
890 String ctxList = parameters.get("list");
891 ctxList = (ctxList.endsWith(LENGTH)) ? ctxList : ctxList + LENGTH;
892 int listLength = getArrayLength(ctx, ctxList);
894 if (listLength == 0) {
895 LOG.debug("List is not in context memory");
898 Set<String> keys = new HashSet<String>();
900 String listPrefix = ctxList.substring(0, ctxList.lastIndexOf("_")) + "[";
901 String listSuffix = "]." + parameters.get("keyName");
903 for (int i = 0; i < listLength; i++) {
904 String keyLocation = listPrefix + i + listSuffix;
905 keys.add(ctx.getAttribute(keyLocation));
908 if (keys.contains(parameters.get("keyValue"))) {
909 LOG.debug("List " + parameters.get("list") + " contains " + parameters.get("keyValue"));
912 LOG.debug("List " + parameters.get("list") + " do not contains " + parameters.get("keyValue"));
916 } catch (Exception ex) {
917 throw new SvcLogicException("ctxListContains failed", ex);
922 * set properties in context memory for a container </br>
923 * parameters with a null or empty key or value are ignored </br>
924 * required parameter root - root + "." + parameters.key
925 * is the key to set the value too value in context memory </br>
926 * optional parameter valueRoot - if set: valueRoot + "." + parameters.value
927 * is the key to get the value from context memory
929 * @param parameters - root (required), valueRoot (optional), properties names and values to be set
930 * @param ctx Reference to context memory
931 * @return success or failure of operation
933 public static String setPropertiesForRoot(Map<String, String> parameters, SvcLogicContext ctx) {
934 LOG.debug("Execute Node \"setPropertiesForRoot\"");
936 checkParameters(parameters, new String[]{"root"}, LOG);
937 } catch (Exception ex) {
941 String root = parameters.get("root");
943 if (StringUtils.isEmpty(root)) {
947 // set context memory to the the properties passed with root as prefix
948 setParameterValuesToRoot(parameters, ctx, root);
953 private static boolean setParameterValuesToRoot(Map<String, String> parameters, SvcLogicContext ctx, String root) {
954 boolean changeFlag = false;
955 String valueRoot = parameters.get("valueRoot");
957 for (Map.Entry<String, String> entry : parameters.entrySet()) {
958 // ignore if it's the root parameter
959 if (!entry.getKey().equals("root")) {
960 String keyToBeSet = root + "." + entry.getKey();
961 String valueToBeSet = "";
963 if (StringUtils.isEmpty(valueRoot)) {
964 valueToBeSet = entry.getValue();
966 valueToBeSet = ctx.getAttribute(valueRoot + "." + entry.getValue());
969 LOG.debug("Setting context memory: " + keyToBeSet + " = " + valueToBeSet);
971 if (!StringUtils.isEmpty(entry.getKey()) && !StringUtils.isEmpty(valueToBeSet)) {
972 ctxSetAttribute(ctx, keyToBeSet, valueToBeSet);
982 * takes container list and set the properties with the value provided </br>
983 * parameters with a null or empty key or value are ignored </br>
984 * required parameters </br>
985 * prefixKey + "." + parameters.key is the key to set the value too value in context memory </br>
986 * prefixKey + "[index]." + keyName is the key of the entry in the list in context memory </br>
987 * keyValue is the value of the key of the list entry in context memory (must be actual value)</br>
988 * optional parameter valuePrefixKey - if set: valuePrefixKey + "." + parameters.value
989 * is the key to get the value from context memory
991 * @param parameters </br>
992 * - prefixKey e.g "service-data.universal-cpe-ft.l2-switch-interfaces" </br>
993 * - keyName e.g "name" </br>
994 * - keyValue e.g "WAN1" (must be actual value and not use the prefixKey as root) </br>
995 * - valuePrefixKey (optional) e.g "input.universal-cpe-ft.l2-switch-interfaces[1] </br>
996 * - properties to be set, values for the properties </br>
997 * @param ctx reference to context memory
998 * @return success or failure of operation
1000 public static String setPropertiesForList(Map<String, String> parameters, SvcLogicContext ctx) {
1001 LOG.debug("Execute Node \"setPropertiesForList\"");
1003 checkParameters(parameters, new String[]{"prefixKey", "keyName", "keyValue"}, LOG);
1004 } catch (Exception e) {
1005 LOG.error("a required parameter is missing");
1009 String prefixKey = parameters.get("prefixKey");
1010 String keyName = parameters.get("keyName");
1011 String keyValue = parameters.get("keyValue");
1013 if (StringUtils.isEmpty(keyName) || StringUtils.isEmpty(keyValue) || StringUtils.isEmpty(prefixKey)) {
1014 LOG.error("a required parameters value is empty or null");
1018 int listLength = getArrayLength(ctx, prefixKey);
1020 Map<String, String> containParams = new HashMap<>();
1021 containParams.put("list", prefixKey);
1022 containParams.put("keyName", keyName);
1023 containParams.put("keyValue", keyValue);
1025 String valuePrefixKey = parameters.get("valuePrefixKey");
1028 // create new list in context memory
1029 if (listLength == 0) {
1030 // since there's no length found make sure there's no current data at prefixKey in context memory
1031 Map<String, String> map = ctxGetBeginsWith(ctx, prefixKey);
1033 if (map.size() == 0) {
1034 setNewEntryInList(parameters, ctx, keyName, keyValue, prefixKey, valuePrefixKey, listLength);
1036 LOG.error("there was no length for the list parameter set in context memory "
1037 + "but " + map.size() + " entries were found in context memory "
1038 + "where the key begins with: " + prefixKey);
1042 } else if (ctxListContains(containParams, ctx) == "false") {
1043 setNewEntryInList(parameters, ctx, keyName, keyValue, prefixKey, valuePrefixKey, listLength);
1044 } else if (ctxListContains(containParams, ctx) == "true") {
1045 // else update the context memory with the properties passed in at the right index level
1046 String listPrefix = prefixKey + "[";
1047 String listSuffix = "].";
1049 for (int i = 0; i < listLength; i++) {
1050 String listRootWithIndex = listPrefix + i + listSuffix;
1051 String listKeyName = listRootWithIndex + keyName;
1052 String valueAtListIndexKey = ctx.getAttribute(listKeyName);
1054 if (valueAtListIndexKey.equals(keyValue)) {
1055 setParametersToCtxList(parameters, ctx, listRootWithIndex, valuePrefixKey);
1059 } catch (SvcLogicException e) {
1060 LOG.error("Call to ctxListContains failed: " + e.getMessage());
1068 private static void setNewEntryInList(Map<String, String> parameters, SvcLogicContext ctx, String keyName,
1069 String keyValue, String prefixKey, String valuePrefixKey, int listLength) {
1070 String prefixKeyWithIndex = prefixKey + "[" + listLength + "].";
1071 String listKeyName = prefixKeyWithIndex + keyName;
1074 LOG.debug("Setting context memory, new list entry with key: " + listKeyName + " = " + keyValue);
1075 ctxSetAttribute(ctx, listKeyName, keyValue);
1077 // set the other parameters
1078 setParametersToCtxList(parameters, ctx, prefixKeyWithIndex, valuePrefixKey);
1080 // set length of list
1081 String ListLengthKeyName = prefixKey + LENGTH;
1083 ctxSetAttribute(ctx, prefixKey + LENGTH, listLength + 1);
1084 LOG.debug("Updated _length: " + prefixKey + "_length is now " + ctx.getAttribute(ListLengthKeyName));
1088 * helper function to set the parameter properties for list at the provided prefix key
1093 * @return true if any new context memory was added and or modified
1095 private static boolean setParametersToCtxList(Map<String, String> parameters, SvcLogicContext ctx, String prefixKeyWithIndex,
1096 String valuePrefixKey) {
1097 boolean changeFlag = false;
1099 for (Map.Entry<String, String> entry : parameters.entrySet()) {
1100 if (! (entry.getKey().equals("prefixKey") ||
1101 entry.getKey().equals("keyName") ||
1102 entry.getKey().equals("keyValue")) ||
1103 entry.getKey().equals("valuePrefixKey")) {
1105 String keyToBeSet = prefixKeyWithIndex + entry.getKey();
1106 String valueToBeSet = "";
1108 if (StringUtils.isEmpty(valuePrefixKey)) {
1109 valueToBeSet = entry.getValue();
1111 valueToBeSet = ctx.getAttribute(valuePrefixKey + "." + entry.getValue());
1114 LOG.debug("Setting context memory: " + keyToBeSet + " = " + valueToBeSet);
1116 // only set context memory if properties key and value are not empty or null
1117 if (!StringUtils.isEmpty(entry.getKey()) && !StringUtils.isEmpty(valueToBeSet)) {
1118 ctxSetAttribute(ctx, keyToBeSet, valueToBeSet);
1127 public static String containsKey(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1128 String key = parameters.get("key");
1129 Boolean keyFound = ctx.getAttributeKeySet().contains(key);