c73315f4f17e6feec6ecf031dc14789f871b1b95
[ccsdk/sli/core.git] / sliPluginUtils / provider / src / main / java / org / openecomp / sdnc / sli / SliPluginUtils / SliPluginUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.sdnc.sli.SliPluginUtils;
23
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.PrintStream;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.Properties;
35 import java.util.Set;
36 import java.util.UUID;
37
38 import org.apache.commons.lang3.StringUtils;
39 import org.openecomp.sdnc.sli.SvcLogicContext;
40 import org.openecomp.sdnc.sli.SvcLogicException;
41 import org.openecomp.sdnc.sli.SvcLogicJavaPlugin;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * A utility class used to streamline the interface between Java plugins,
47  * the Service Logic Context, and Directed Graphs.
48  * @version 7.0.1
49  * @see org.openecomp.sdnc.sli.SvcLogicContext
50  */
51 public class SliPluginUtils implements SvcLogicJavaPlugin {
52         public enum LogLevel {
53                 TRACE, DEBUG, INFO, WARN, ERROR;
54         }
55
56         private static final Logger LOG = LoggerFactory.getLogger(SliPluginUtils.class);
57
58
59         // ========== CONSTRUCTORS ==========
60
61         public SliPluginUtils() {}
62
63         public SliPluginUtils( Properties props ) {}
64
65
66
67         // ========== CONTEXT MEMORY FUNCTIONS ==========
68
69         /**
70          * Removes 1 or more elements from a list in context memory.
71          * <p>
72          * Values are removed based on either the index in the list, a key-value
73          * pair, or a list of key-value pairs that all must match in the element.
74          * @param parameters
75          * @param ctx Reference to context memory
76          * @throws SvcLogicException All exceptions are wrapped in
77          * SvcLogicException for compatibility with SLI.
78          * @since 7.0.1
79          */
80         public void ctxListRemove( Map<String,String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
81                 try{
82                         LOG.debug( "ENTERING Execute Node \"ctxListRemove\"" );
83
84                         // Validate, Log, & read parameters
85                         checkParameters(parameters, new String[]{"list_pfx"}, LOG);
86                         logExecuteNodeParameters(parameters, LOG, LogLevel.DEBUG);
87                         String list_pfx = parameters.get("list_pfx");
88                         String param_index = parameters.get("index");
89                         String param_key = parameters.get("key");
90                         String param_value = parameters.get("value");
91                         String param_keys_length = parameters.get("keys_length");
92
93                         // Initialize context memory list mimic
94                         SvcLogicContextList list;
95
96                         // Process based on input parameters:
97                         //   index: remove object at specific index
98                         //   key & value: remove all objects with key-value pair
99                         //   keys_length: remove all objects that match all key-value pairs
100                         //                in list
101                         if( param_index != null ) {
102                                 // Parse index
103                                 LOG.trace("executing remove by index logic");
104                                 int index;
105                                 try {
106                                         index = Integer.parseInt(param_index);
107                                 }
108                                 catch( NumberFormatException e ) {
109                                         throw new IllegalArgumentException("\"index\" parameter is not a number. index = " + param_index, e);
110                                 }
111
112                                 // Extract list from context memory & remove object @ index
113                                 LOG.trace("extracting list from context memory");
114                                 list = SvcLogicContextList.extract(ctx, list_pfx);
115                                 LOG.trace("removing elements from list");
116                                 list.remove(index);
117                         }
118                         else if( param_value != null ) {
119                                 if( param_key == null ) { param_key = ""; }
120
121                                 // Extract list from context memory & remove objects with
122                                 // key-value pair
123                                 LOG.trace("executing remove by key-value pair logic");
124                                 LOG.trace("extracting list from context memory");
125                                 list = SvcLogicContextList.extract(ctx, list_pfx);
126                                 LOG.trace("removing elements from list");
127                                 list.remove( param_key, param_value );
128                         }
129                         else if( param_keys_length != null ) {
130                                 // Parse keys_length
131                                 LOG.trace("executing remove by key-value pair list logic");
132                                 int keys_length;
133                                 try {
134                                         keys_length = Integer.parseInt(param_keys_length);
135                                 }
136                                 catch( NumberFormatException e ) {
137                                         throw new IllegalArgumentException("\"keys_length\" parameters is not a number. keys_length = " + param_keys_length, e);
138                                 }
139
140                                 // Obtain key-value pairs to check from parameters
141                                 LOG.trace("reading keys parameter list");
142                                 HashMap<String,String> keys_values = new HashMap<String,String>();
143                                 for( int i = 0; i < keys_length; i++ ) {
144                                         keys_values.put(parameters.get("keys[" + i + "].key"), parameters.get("keys[" + i + "].value"));
145                                 }
146
147                                 // Extract list from context memory & remove objects with all
148                                 // key-value pairs matching
149                                 LOG.trace("extracting list from context memory");
150                                 list = SvcLogicContextList.extract(ctx, list_pfx);
151                                 LOG.trace("removing elements from list");
152                                 list.remove(keys_values);
153                         }
154                         else {
155                                 throw new IllegalArgumentException("Required parameters missing. Requires one of: index, key & value, or keys_length array");
156                         }
157
158                         // Remove index from list
159                         LOG.trace("writing list back into context memory");
160                         list.writeToContext(ctx);
161                 }
162                 catch( Exception e ) {
163                         throw new SvcLogicException( "An error occurred in the ctxListRemove Execute node", e );
164                 }
165                 finally {
166                         LOG.debug( "EXITING Execute Node \"ctxListRemove\"" );
167                 }
168         }
169
170     /**
171      * ctxSortList
172      * @param parameters - the set of required parameters must contain list and delimiter.
173      * @param ctx Reference to context memory
174      * @throws SvcLogicException if a required parameter is missing an exception is thrown
175      */
176         public void ctxSortList( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
177                 checkParameters(parameters, new String[]{"list","delimiter"}, LOG);
178                 ArrayList<SortableCtxListElement> list = new ArrayList<SortableCtxListElement>();
179
180                 String[] sort_fields = null;
181                 if( parameters.containsKey("sort-fields") ) {
182                         sort_fields = parameters.get("sort-fields").split(parameters.get("delimiter"), 0);
183                 }
184
185                 String ctx_list_str = parameters.get("list");
186                 int listSz = getArrayLength(ctx, ctx_list_str);
187
188
189
190                 for( int i = 0; i < listSz; i++ ) {
191                         list.add( new SortableCtxListElement(ctx, ctx_list_str + '[' + i + ']', sort_fields) );
192                 }
193                 Collections.sort(list);
194
195                 ctxBulkErase(ctx, ctx_list_str);
196                 int i = 0;
197                 for( SortableCtxListElement list_element : list ) {
198                         for( Map.Entry<String,String> entry : list_element.child_elements.entrySet() ) {
199                                 if( sort_fields == null ) {
200                                         ctx.setAttribute(ctx_list_str + '[' + i + ']', entry.getValue());
201                                 }
202                                 else {
203                                         ctx.setAttribute(ctx_list_str + '[' + i + "]." + entry.getKey(), entry.getValue());
204                                 }
205                         }
206                         i++;
207                 }
208                 // Reset list length (removed by ctxBulkErase above)
209                 ctx.setAttribute(ctx_list_str+"_length",  ""+listSz);
210         }
211
212     /**
213      * generates a UUID and writes it to context memory
214      * @param parameters - ctx-destination is a required parameter
215      * @param ctx Reference to context memory
216      * @throws SvcLogicException thrown if a UUID cannot be generated or if ctx-destination is missing or null
217      */
218         public void generateUUID( Map<String, String> parameters, SvcLogicContext ctx )  throws SvcLogicException {
219                 checkParameters(parameters, new String[]{"ctx-destination"}, LOG);
220                 ctx.setAttribute(parameters.get("ctx-destination"), UUID.randomUUID().toString() );
221         }
222
223         /**
224          * Provides substring functionality to Directed Graphs.
225          * <p>
226          * Calls either String.substring(String beginIndex) or
227          * String.substring(String beginInded, String endIndex) if the end-index
228          * is present or not.
229          * @param parameters HashMap<String,String> of parameters passed by the DG to this function
230          * <table border="1">
231          *      <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
232          *      <tbody>
233          *              <tr><td>string</td><td>Mandatory</td><td>String to perform substring on</td></tr>
234          *              <tr><td>result</td><td>Mandatory</td><td>Key in context memory to populate the resulting string in</td></tr>
235          *              <tr><td>begin-index</td><td>Mandatory</td><td>Beginning index to pass to Java substring function</td></tr>
236          *              <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>
237          *      </tbody>
238          * </table>
239          * @param ctx Reference to context memory
240          * @throws SvcLogicException
241          * @since 8.0.1
242          * @see SliPluginUtils#substring(Map, SvcLogicContext)
243          */
244         @Deprecated
245         public void substring( Map<String, String> parameters, SvcLogicContext ctx ) throws SvcLogicException {
246                 try {
247                         checkParameters( parameters, new String[]{"string","begin-index","result"}, LOG );
248                         final String string = parameters.get("string");
249                         final String result = parameters.get("result");
250                         final String begin = parameters.get("begin-index");
251                         final String end = parameters.get("end-index");
252
253                         if( StringUtils.isEmpty(end) ) {
254                                 ctx.setAttribute( result, string.substring(Integer.parseInt(begin)) );
255                         }
256                         else {
257                                 ctx.setAttribute( result, string.substring(Integer.parseInt(begin), Integer.parseInt(end)) );
258                         }
259                 }
260                 catch( Exception e ) {
261                         throw new SvcLogicException( "An error occurred while the Directed Graph was performing a substring", e );
262                 }
263         }
264
265
266
267         // ========== PUBLIC STATIC UTILITY FUNCTIONS ==========
268
269         /**
270          * Throws an exception and writes an error to the log file if a required
271          * parameters is not found in the parametersMap.
272          * <p>
273          * Use at the beginning of functions that can be called by Directed Graphs
274          * and can take parameters to verify that all parameters have been provided
275          * by the Directed Graph.
276          * @param parametersMap parameters Map passed to this node
277          * @param requiredParams Array of parameters required by the calling function
278          * @param log Reference to Logger to log to
279          * @throws SvcLogicException if a String in the requiredParams array is
280          * not a key in parametersMap.
281          * @since 1.0
282          */
283         public static final void checkParameters(Map<String, String> parametersMap, String[] requiredParams, Logger log) throws SvcLogicException {
284         if( requiredParams == null || requiredParams.length < 1){
285             log.debug("required parameters was empty, exiting early.");
286             return;
287         }
288         if (parametersMap == null || parametersMap.keySet().size() < 1){
289             String errorMessage = "This method requires the parameters [" +   StringUtils.join(requiredParams,",") + "], but no parameters were passed in.";
290             log.error(errorMessage);
291             throw new SvcLogicException(errorMessage);
292         }
293
294         for (String param : requiredParams) {
295             if (!parametersMap.containsKey(param)) {
296                 String errorMessage = "Required parameter \"" + param + "\" was not found in parameter list.";
297                 log.error(errorMessage);
298                 log.error("Total list of required parameters is [" + StringUtils.join(requiredParams, ",") + "].");
299                 throw new SvcLogicException(errorMessage);
300             }
301         }
302         }
303
304         /**
305          * Removes all key-value pairs with keys that begin with pfx
306          * @param ctx Reference to context memory
307          * @param pfx Prefix of key-value pairs to remove
308          * @since 1.0
309          */
310         public static final void ctxBulkErase( SvcLogicContext ctx, String pfx ) {
311                 ArrayList<String> Keys = new ArrayList<String>( ctx.getAttributeKeySet() );
312                 for( String key : Keys ) {
313                         if( key.startsWith( pfx ) ) {
314                                 ctx.setAttribute( pfx + key.substring(pfx.length()) , null);
315                         }
316                 }
317         }
318
319         /**
320          * Copies all context memory key-value pairs that start with src_pfx to
321          * the keys that start with dest_pfx + suffix, where suffix is the result
322          * of {@code key.substring(src_pfx.length())}.
323          * <p>
324          * Does NOT guarantee removal of all keys at the destination before
325          * copying, but will overwrite any destination keys that have a
326          * corresponding source key. Use {@link #ctxBulkErase(SvcLogicContext, String) ctxBulkErase}
327          * before copy to erase destination root before copying from source.
328          * @param ctx Reference to context memory.
329          * @param src_pfx Prefix of the keys to copy values from.
330          * @param dest_pfx Prefix of the keys to copy values to.
331          * @since 1.0
332          */
333         public static final void ctxBulkCopy( SvcLogicContext ctx, String src_pfx, String dest_pfx ) {
334                 // Remove trailing period from dest_pfx
335                 if( dest_pfx.charAt(dest_pfx.length()-1) == '.' ) {
336                         dest_pfx = dest_pfx.substring(0,dest_pfx.length()-1);
337                 }
338
339                 // For each context key that begins with src_pfx, set the value of the
340                 // key dest_pfx + the suffix of the key to the key's value
341                 ArrayList<String> Keys = new ArrayList<String>(ctx.getAttributeKeySet());
342                 for( String key : Keys ) {
343                         if( key.startsWith(src_pfx) ) {
344                                 // Get suffix (no leading period)
345                                 String suffix = key.substring(src_pfx.length());
346                                 if( suffix.charAt(0) == '.') {
347                                         suffix = suffix.substring(1);
348                                 }
349
350                                 // Set destination's value to key's value
351                                 ctx.setAttribute(dest_pfx + '.' + suffix, ctx.getAttribute(key));
352                         }
353                 }
354         }
355
356         /**
357          * Creates and returns a {@code Map<String, String>} that is a subset of
358          * context memory where all keys begin with the prefix.
359          * @param ctx Reference to context memory.
360          * @param prefix Returned map's keys should all begin with this value.
361          * @return A {@code Map<String, String>} containing all the key-value pairs
362          * in ctx whose key begins with prefix.
363          */
364         public static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
365                 Map<String, String> prefixMap = new HashMap<String, String>();
366
367                 for( String key : ctx.getAttributeKeySet() ) {
368                         if( key.startsWith(prefix) ) {
369                                 prefixMap.put( key, ctx.getAttribute(key) );
370                         }
371                 }
372
373                 return prefixMap;
374         }
375
376         /**
377          * Returns true if key's value in context memory is "" or if it doesn't
378          * exist in context memory.
379          * @param ctx Reference to context memory.
380          * @param key Key to search for.
381          * @return true if key's value in context memory is "" or if it doesn't
382          * exist in context memory.
383          * @since 1.0
384          */
385         public static final boolean ctxKeyEmpty( SvcLogicContext ctx, String key ) {
386                 String value = ctx.getAttribute(key);
387                 return value == null || value.isEmpty();
388         }
389
390         /**
391          * Adds all key-value pairs in the entries Map to context memory.
392          * @param ctx Reference to context memory. Value's {@code toString()}
393          * function is used to add it.
394          * @param entries {@code Map<String, ?>} of key-value pairs to add to
395          * context memory. Value's {@code toString()} function is used to add it.
396          * @return Reference to context memory to be used for function chaining.
397          */
398         public static final SvcLogicContext ctxPutAll( SvcLogicContext ctx, Map<String, ?> entries ) {
399                 for( Map.Entry<String, ?> entry : entries.entrySet() ) {
400                         ctxSetAttribute( ctx, entry.getKey(), entry.getValue() );
401                         //ctx.setAttribute(entry.getKey(), entry.getValue().toString());
402                 }
403
404                 return ctx;
405         }
406
407         /**
408          * Sets a key in context memory to the output of object's toString(). The
409          * key is deleted from context memory if object is null.
410          * @param ctx Reference to context memory.
411          * @param key Key to set.
412          * @param object Object whose toString() will be the value set
413          */
414         public static final void ctxSetAttribute( SvcLogicContext ctx, String key, Object object ) {
415                 if( object == null ) {
416                         ctx.setAttribute(key, null);
417                 }
418                 else {
419                         ctx.setAttribute(key, object.toString());
420                 }
421         }
422
423         /**
424          * Sets a key in context memory to the output of object's toString().
425          * <p>
426          * The key is deleted from context memory if object is null. The key and
427          * value set in context memory are logged to the Logger at the provided
428          * logLevel level.
429          * @param <O> Any Java object
430          * @param ctx Reference to context memory.
431          * @param key Key to set.
432          * @param obj Object whose toString() will be the value set
433          * @param LOG Logger to log to
434          * @param logLevel level to log at in Logger
435          */
436         public static final <O extends Object> void ctxSetAttribute( SvcLogicContext ctx, String key, O obj, Logger LOG, LogLevel logLevel ) {
437                 String value = Objects.toString( obj, null );
438                 ctx.setAttribute( key, value );
439                 if( logLevelIsEnabled(LOG, logLevel ) ) {
440                         if( value == null ) {
441                                 logMessageAtLevel( LOG, logLevel, "Deleting " + key );
442                         }
443                         else {
444                                 logMessageAtLevel( LOG, logLevel, "Setting " + key + " = " + value );
445                         }
446                 }
447         }
448
449         /**
450          * Utility function used to get an array's length from context memory.
451          * Will return 0 if key doesn't exist in context memory or isn't numeric.
452          * <p>
453          * Use to obtain a context memory array length without having to worry
454          * about throwing a NumberFormatException.
455          * @param ctx Reference to context memory
456          * @param key Key in context memory whose value is the array's length. If
457          * the key doesn't end in "_length", then "_length is appended.
458          * @param log Reference to Logger to log to
459          * @return The array length or 0 if the key is not found in context memory.
460          * @since 1.0
461          */
462         public static final int getArrayLength( SvcLogicContext ctx, String key ) {
463                 return getArrayLength(ctx, key, null, null, null);
464         }
465
466         /**
467          * Utility function used to get an array's length from context memory.
468          * Will return 0 if key doesn't exist in context memory or isn't numeric
469          * and print the provided log message to the configured log file.
470          * <p>
471          * Use to obtain a context memory array length without having to worry
472          * about throwing a NumberFormatException.
473          * @param ctx Reference to context memory.
474          * @param key Key in context memory whose value is the array's length. If
475          * the key doesn't end in "_length", then "_length is appended.
476          * @param log Reference to Logger to log to. Doesn't log if null.
477          * @param logLevel Logging level to log the message at if the context
478          * memory key isn't found. Doesn't log if null.
479          * @param log_message Message to log if the context memory key isn't found.
480          * Doesn't log if null.
481          * @return The array length or 0 if the key is not found in context memory.
482          * @since 1.0
483          */
484         public static final int getArrayLength( SvcLogicContext ctx, String key, Logger log, LogLevel logLevel, String log_message ) {
485                 String ctxKey = ( key.endsWith("_length") ) ? key : key + "_length";
486                 try {
487                         return Integer.parseInt(ctx.getAttribute(ctxKey));
488                 }
489                 catch( NumberFormatException e ) {
490                         if( log != null && logLevel != null && log_message != null ) {
491                                 switch( logLevel ) {
492                                         case TRACE:
493                                                 log.trace(log_message);
494                                         case DEBUG:
495                                                 log.debug(log_message);
496                                                 break;
497                                         case INFO:
498                                                 log.info(log_message);
499                                                 break;
500                                         case WARN:
501                                                 log.warn(log_message);
502                                                 break;
503                                         case ERROR:
504                                                 log.error(log_message);
505                                                 break;
506                                 }
507                         }
508                 }
509
510                 return 0;
511         }
512
513         /**
514          * Prints sorted context memory key-value pairs to the log file at the log
515          * level. Returns immediately if the log level isn't enabled.
516          * <p>
517          * O(n log(n)) time where n = size of context memory
518          * @param ctx Reference to context memory
519          * @param log Reference to Logger to log to
520          * @param logLevel Logging level to log the context memory key-value pairs
521          * at.
522          * @since 1.0
523          */
524         public static final void logContextMemory( SvcLogicContext ctx, Logger log, LogLevel logLevel ) {
525                 logLevelIsEnabled( log, logLevel );
526
527                 // Print sorted context memory key-value pairs to the log
528                 ArrayList<String> keys = new ArrayList<String>(ctx.getAttributeKeySet());
529                 Collections.sort(keys);
530                 for( String key : keys ) {
531                         logMessageAtLevel( log, logLevel, key + " = " + ctx.getAttribute(key) );
532                 }
533         }
534
535
536
537         // ========== PRIVATE FUNCTIONS ==========
538
539         // TODO: javadoc
540         /**
541          *
542          * @param parameters
543          * @param log
544          * @param loglevel
545          * @since 7.0.1
546          */
547         public static final void logExecuteNodeParameters( Map<String,String> parameters, Logger log, LogLevel loglevel ) {
548                 logLevelIsEnabled( log, loglevel );
549
550                 for( Map.Entry<String,String> param : parameters.entrySet() ) {
551                         logMessageAtLevel( log, loglevel, "PARAM: " + param.getKey() + " = " + param.getValue() );
552                 }
553         }
554
555         // TODO: javadoc
556         /**
557          * Returns true if the loglevel is enabled. Otherwise, returns false.
558          * @param log Reference to logger
559          * @param loglevel Log level to check if enabled
560          * @return True if the loglevel is enabled. Otherwise, false
561          * @since 7.0.1
562          */
563         private static final boolean logLevelIsEnabled( Logger log, LogLevel loglevel ) {
564                 // Return immediately if logging level isn't enabled
565                 switch( loglevel ) {
566                         case TRACE:
567                                 if( log.isTraceEnabled() ) { return true; }
568                                 return false;
569                         case DEBUG:
570                                 if( log.isDebugEnabled() ) { return true; }
571                                 return false;
572                         case INFO:
573                                 if( log.isInfoEnabled() ) { return true; }
574                                 return false;
575                         case WARN:
576                                 if( log.isWarnEnabled() ) { return true; }
577                                 return false;
578                         case ERROR:
579                                 if( log.isErrorEnabled() ) { return true; }
580                                 return false;
581                         default:
582                                 throw new IllegalArgumentException("Unknown LogLevel: " + loglevel.toString());
583                 }
584         }
585
586         // TODO: javadoc
587         /**
588          *
589          * @param log
590          * @param loglevel
591          * @param msg
592          * @since 7.0.1
593          */
594         private static final void logMessageAtLevel( Logger log, LogLevel loglevel, String msg ) {
595                 switch( loglevel ) {
596                         case TRACE:
597                                 log.trace(msg);
598                                 return;
599                         case DEBUG:
600                                 log.debug(msg);
601                                 return;
602                         case INFO:
603                                 log.info(msg);
604                                 return;
605                         case WARN:
606                                 log.warn(msg);
607                                 return;
608                         case ERROR:
609                                 log.error(msg);
610                                 return;
611                 }
612         }
613
614
615
616         // ========== LOCAL CLASSES ==========
617
618         private class SortableCtxListElement implements Comparable<SortableCtxListElement> {
619                 HashMap<String,String> child_elements = new HashMap<String,String>();
620                 String[] sort_fields;
621
622                 public SortableCtxListElement( SvcLogicContext ctx, String root, String[] sort_fields ) {
623                         this.sort_fields = sort_fields;
624
625                         for( String key : ctx.getAttributeKeySet() ) {
626                                 if( key.startsWith(root) ) {
627                                         if( key.length() == root.length() ) {
628                                                 child_elements.put("", ctx.getAttribute(key));
629                                                 break;
630                                         }
631                                         else {
632                                                 child_elements.put(key.substring(root.length()+1), ctx.getAttribute(key));
633                                         }
634                                 }
635                         }
636                 }
637
638                 @Override
639                 public int compareTo(SortableCtxListElement arg0) {
640                         if( sort_fields == null ) {
641                                 return this.child_elements.get("").compareTo(arg0.child_elements.get(""));
642                         }
643
644                         for( String field : this.sort_fields ) {
645                                 int result = this.child_elements.get(field).compareTo(arg0.child_elements.get(field));
646                                 if( result != 0 ) {
647                                         return result;
648                                 }
649                         }
650
651                         return 0;
652                 }
653         }
654
655         /**
656      * Creates a file that contains the content of context memory.
657      * @param parameters - must contain the parameter filename
658      * @param ctx Reference to context memory
659      * @throws SvcLogicException thrown if file cannot be created or if parameters are missing
660      */
661         public static void printContext(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
662                 if (parameters == null || parameters.isEmpty()) {
663                         throw new SvcLogicException("no parameters passed");
664                 }
665
666                 checkParameters(parameters, new String[]{"filename"}, LOG);
667
668                 String fileName = parameters.get("filename");
669
670
671                 try (FileOutputStream fstr = new FileOutputStream(new File(fileName));
672                          PrintStream pstr = new PrintStream(fstr, true);)
673                 {
674                         pstr.println("#######################################");
675                         for (String attr : ctx.getAttributeKeySet()) {
676                                 pstr.println(attr + " = " + ctx.getAttribute(attr));
677                         }
678                 } catch (Exception e) {
679                         throw new SvcLogicException("Cannot write context to file " + fileName, e);
680                 }
681
682
683         }
684
685          /**
686      * Checks context memory for a set of required parameters
687      * Every parameter aside from prefix will be treated as mandatory
688      * @param parameters HashMap<String,String> of parameters passed by the DG to this function
689      * <table border="1">
690      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th></thead>
691      *  <tbody>
692      *      <tr><td>prefix</td><td>Optional</td><td>the prefix will be added to each parameter</td></tr>
693      *  </tbody>
694      * </table>
695      * @param ctx Reference to context memory
696      * @throws SvcLogicException
697      * @since 11.0.2
698      */
699         public static void requiredParameters(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
700                 if (parameters == null || parameters.keySet().size() < 1) {
701             String errorMessage = "requiredParameters should not be called if the parameters hashmap is null or empty!";
702             LOG.error(errorMessage);
703             throw new SvcLogicException(errorMessage);
704                 }
705                 String prefixValue = null;
706                 String prefix = "prefix";
707                 if(parameters.containsKey(prefix)){
708                     prefixValue = parameters.get(prefix);
709                     parameters.remove(prefix);
710                 }
711                 checkParameters(prefixValue, ctx.getAttributeKeySet(), parameters.keySet(), LOG);
712         }
713
714     private static void checkParameters(String prefixValue, Set<String> ctx, Set<String> parameters, Logger log) throws SvcLogicException {
715         for (String param : parameters) {
716             if (prefixValue != null) {
717                 param = prefixValue + param;
718             }
719             if (!ctx.contains(param)) {
720                 String errorMessage = "This method requires the parameters [" + StringUtils.join(parameters, ",")
721                         + "], but " + param + " was not passed in.";
722                 log.error(errorMessage);
723                 throw new SvcLogicException(errorMessage);
724             }
725         }
726     }
727
728     /**
729      *  is in a different DG invocation just before/after we call NCS and set the state to InProgress
730      */
731     /**
732     * setTime write the current date time to a string located at outputPath
733     * @param parameters - requires outputPath to not be null
734     * @param ctx Reference to context memory
735     * @throws SvcLogicException if a required parameter is missing an exception is thrown
736     */
737     public static void setTime(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException
738     {
739         checkParameters(parameters, new String[] { "outputPath" }, LOG);
740
741         // Set the DateFormat
742         // "2015-03-16T12:18:35.138Z"
743         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
744
745         // Parse the date
746         String ctxVariable = parameters.get("outputPath");
747         try {
748             String dateTime = format.format(new Date());
749             ctx.setAttribute(ctxVariable, dateTime);
750         } catch (Exception ex) {
751             throw new SvcLogicException("problem with setTime", ex);
752         }
753     }
754 }